2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
14 int32_t mp4ff_total_tracks(const mp4ff_t * f)
16 return f->total_tracks;
19 static int32_t mp4ff_read_data(mp4ff_t * f, void *data, uint32_t size)
23 result = f->stream->read(f->stream->user_data, data, size);
26 f->stream->read_error++;
28 f->current_position += size;
33 /* parse atom header size */
34 static int32_t mp4ff_atom_get_size(const int8_t * data)
39 a = (uint8_t) data[0];
40 b = (uint8_t) data[1];
41 c = (uint8_t) data[2];
42 d = (uint8_t) data[3];
44 result = (a << 24) | (b << 16) | (c << 8) | d;
45 return (int32_t) result;
48 static uint64_t mp4ff_read_int64(mp4ff_t * f)
54 mp4ff_read_data(f, data, 8);
56 for (i = 0; i < 8; i++) {
57 result |= ((uint64_t) data[i]) << ((7 - i) * 8);
63 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
64 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1,
65 const int8_t c1, const int8_t d1,
66 const int8_t a2, const int8_t b2,
67 const int8_t c2, const int8_t d2)
69 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
77 #define TRACK_SYSTEM 3
78 #define TRACK_UNKNOWN 0
80 /* atoms with subatoms */
88 #define ATOM_ILST 8 /* iTunes Metadata list */
90 #define ATOM_ARTIST 10
91 #define ATOM_WRITER 11
95 #define ATOM_COMMENT 15
96 #define ATOM_GENRE1 16
99 #define ATOM_COMPILATION 19
100 #define ATOM_GENRE2 20
101 #define ATOM_TEMPO 21
102 #define ATOM_COVER 22
107 #define SUBATOMIC 128
109 /* atoms without subatoms */
110 #define ATOM_FTYP 129
111 #define ATOM_MDAT 130
112 #define ATOM_MVHD 131
113 #define ATOM_TKHD 132
114 #define ATOM_TREF 133
115 #define ATOM_MDHD 134
116 #define ATOM_VMHD 135
117 #define ATOM_SMHD 136
118 #define ATOM_HMHD 137
119 #define ATOM_STSD 138
120 #define ATOM_STTS 139
121 #define ATOM_STSZ 140
122 #define ATOM_STZ2 141
123 #define ATOM_STCO 142
124 #define ATOM_STSC 143
125 #define ATOM_MP4A 144
126 #define ATOM_MP4V 145
127 #define ATOM_MP4S 146
128 #define ATOM_ESDS 147
129 #define ATOM_META 148 /* iTunes Metadata box */
130 #define ATOM_NAME 149 /* iTunes Metadata name box */
131 #define ATOM_DATA 150 /* iTunes Metadata data box */
132 #define ATOM_CTTS 151
133 #define ATOM_FRMA 152
134 #define ATOM_IVIV 153
135 #define ATOM_PRIV 154
136 #define ATOM_USER 155
138 #define ATOM_ALBUM_ARTIST 157
139 #define ATOM_CONTENTGROUP 158
140 #define ATOM_LYRICS 159
141 #define ATOM_DESCRIPTION 160
142 #define ATOM_NETWORK 161
143 #define ATOM_SHOW 162
144 #define ATOM_EPISODENAME 163
145 #define ATOM_SORTTITLE 164
146 #define ATOM_SORTALBUM 165
147 #define ATOM_SORTARTIST 166
148 #define ATOM_SORTALBUMARTIST 167
149 #define ATOM_SORTWRITER 168
150 #define ATOM_SORTSHOW 169
151 #define ATOM_SEASON 170
152 #define ATOM_EPISODE 171
153 #define ATOM_PODCAST 172
155 #define ATOM_UNKNOWN 255
156 #define ATOM_FREE ATOM_UNKNOWN
157 #define ATOM_SKIP ATOM_UNKNOWN
159 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
161 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
162 const int8_t c, const int8_t d)
165 if (mp4ff_atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
167 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
169 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
171 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
173 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
175 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
177 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
179 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
181 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
183 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
185 } else if (a == 't') {
186 if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
188 else if (mp4ff_atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
190 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
192 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
194 else if (mp4ff_atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
196 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
198 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
200 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
201 return ATOM_EPISODENAME;
202 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
204 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
206 } else if (a == 's') {
207 if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
209 else if (mp4ff_atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
211 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'd'))
213 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 't', 's'))
215 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
217 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'c'))
219 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'z'))
221 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'z', '2'))
223 else if (mp4ff_atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
225 else if (mp4ff_atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
227 else if (mp4ff_atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
229 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
230 return ATOM_SORTTITLE;
231 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
232 return ATOM_SORTALBUM;
233 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
234 return ATOM_SORTARTIST;
235 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
236 return ATOM_SORTALBUMARTIST;
237 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
238 return ATOM_SORTWRITER;
239 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
240 return ATOM_SORTSHOW;
241 } else if (a == COPYRIGHT_SYMBOL) {
242 if (mp4ff_atom_compare
243 (a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
245 else if (mp4ff_atom_compare
246 (a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
248 else if (mp4ff_atom_compare
249 (a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
251 else if (mp4ff_atom_compare
252 (a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
254 else if (mp4ff_atom_compare
255 (a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
257 else if (mp4ff_atom_compare
258 (a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
260 else if (mp4ff_atom_compare
261 (a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
263 else if (mp4ff_atom_compare
264 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
266 else if (mp4ff_atom_compare
267 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
268 return ATOM_CONTENTGROUP;
269 else if (mp4ff_atom_compare
270 (a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
274 if (mp4ff_atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
276 else if (mp4ff_atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
278 else if (mp4ff_atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
280 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
282 else if (mp4ff_atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
284 else if (mp4ff_atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
286 else if (mp4ff_atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
288 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
290 else if (mp4ff_atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
292 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
294 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
296 else if (mp4ff_atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
298 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
300 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
301 return ATOM_COMPILATION;
302 else if (mp4ff_atom_compare(a, b, c, d, 'c', 't', 't', 's'))
304 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
306 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
308 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
310 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
312 else if (mp4ff_atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
314 else if (mp4ff_atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
316 else if (mp4ff_atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
317 return ATOM_ALBUM_ARTIST;
318 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
319 return ATOM_DESCRIPTION;
320 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
326 /* read atom header, return atom size, atom size is with header included */
327 static uint64_t mp4ff_atom_read_header(mp4ff_t * f, uint8_t * atom_type,
328 uint8_t * header_size)
332 int8_t atom_header[8];
334 ret = mp4ff_read_data(f, atom_header, 8);
338 size = mp4ff_atom_get_size(atom_header);
341 /* check for 64 bit atom size */
344 size = mp4ff_read_int64(f);
346 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5],
347 atom_header[6], atom_header[7]);
351 static int64_t mp4ff_position(const mp4ff_t * f)
353 return f->current_position;
356 static int need_parse_when_meta_only(uint8_t atom_type)
377 static int32_t mp4ff_set_position(mp4ff_t * f, const int64_t position)
379 f->stream->seek(f->stream->user_data, position);
380 f->current_position = position;
385 static void mp4ff_track_add(mp4ff_t * f)
389 if (f->total_tracks > MAX_TRACKS) {
394 f->track[f->total_tracks - 1] = para_calloc(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 para_malloc(f->track[f->total_tracks - 1]->stsz_sample_count
450 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count
451 && !f->stream->read_error; i++) {
452 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
458 static int32_t mp4ff_read_stts(mp4ff_t * f)
461 mp4ff_track_t *p_track;
464 if (f->total_tracks == 0)
467 p_track = f->track[f->total_tracks - 1];
469 if (p_track->stts_entry_count)
472 mp4ff_read_char(f); /* version */
473 mp4ff_read_int24(f); /* flags */
474 p_track->stts_entry_count = mp4ff_read_int32(f);
476 p_track->stts_sample_count = para_malloc(p_track->stts_entry_count
478 p_track->stts_sample_delta = para_malloc(p_track->stts_entry_count
480 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9254 */
481 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
482 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
487 static int32_t mp4ff_read_ctts(mp4ff_t * f)
490 mp4ff_track_t *p_track;
492 if (f->total_tracks == 0)
495 p_track = f->track[f->total_tracks - 1];
496 if (p_track->ctts_entry_count)
499 mp4ff_read_char(f); /* version */
500 mp4ff_read_int24(f); /* flags */
501 p_track->ctts_entry_count = mp4ff_read_int32(f);
503 p_track->ctts_sample_count = para_malloc(p_track->ctts_entry_count
505 p_track->ctts_sample_offset = para_malloc(p_track->ctts_entry_count
508 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9257 */
509 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
510 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
515 static int32_t mp4ff_read_stsc(mp4ff_t * f)
519 if (f->total_tracks == 0)
522 mp4ff_read_char(f); /* version */
523 mp4ff_read_int24(f); /* flags */
524 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
526 f->track[f->total_tracks - 1]->stsc_first_chunk =
527 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
529 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
530 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
532 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
533 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
536 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9255 */
537 f->track[f->total_tracks - 1]->stsc_first_chunk[i] =
539 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] =
541 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] =
548 static int32_t mp4ff_read_stco(mp4ff_t * f)
552 if (f->total_tracks == 0)
555 mp4ff_read_char(f); /* version */
556 mp4ff_read_int24(f); /* flags */
557 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
559 f->track[f->total_tracks - 1]->stco_chunk_offset =
560 para_malloc(f->track[f->total_tracks - 1]->stco_entry_count *
562 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9256 */
563 f->track[f->total_tracks - 1]->stco_chunk_offset[i] =
570 static uint16_t mp4ff_read_int16(mp4ff_t * f)
576 mp4ff_read_data(f, data, 2);
577 a = (uint8_t) data[0];
578 b = (uint8_t) data[1];
580 result = (a << 8) | b;
581 return (uint16_t) result;
584 static uint32_t mp4ff_read_mp4_descr_length(mp4ff_t * f)
587 uint8_t numBytes = 0;
591 b = mp4ff_read_char(f);
593 length = (length << 7) | (b & 0x7F);
594 } while ((b & 0x80) && numBytes < 4);
598 static int32_t mp4ff_read_esds(mp4ff_t * f)
603 if (f->total_tracks == 0)
606 mp4ff_read_char(f); /* version */
607 mp4ff_read_int24(f); /* flags */
609 /* get and verify ES_DescrTag */
610 tag = mp4ff_read_char(f);
613 if (mp4ff_read_mp4_descr_length(f) < 5 + 15) {
623 /* get and verify DecoderConfigDescrTab */
624 if (mp4ff_read_char(f) != 0x04) {
629 temp = mp4ff_read_mp4_descr_length(f);
633 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
634 mp4ff_read_int32(f); //0x15000414 ????
635 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
636 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
638 /* get and verify DecSpecificInfoTag */
639 if (mp4ff_read_char(f) != 0x05) {
644 f->track[f->total_tracks - 1]->decoderConfigLen =
645 mp4ff_read_mp4_descr_length(f);
647 free(f->track[f->total_tracks - 1]->decoderConfig);
648 f->track[f->total_tracks - 1]->decoderConfig =
649 para_malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
650 if (f->track[f->total_tracks - 1]->decoderConfig) {
651 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
652 f->track[f->total_tracks -
653 1]->decoderConfigLen);
655 /* will skip the remainder of the atom */
658 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
661 uint8_t atom_type = 0;
662 uint8_t header_size = 0;
664 if (f->total_tracks == 0)
667 for (i = 0; i < 6; i++) {
668 mp4ff_read_char(f); /* reserved */
670 /* data_reference_index */ mp4ff_read_int16(f);
672 mp4ff_read_int32(f); /* reserved */
673 mp4ff_read_int32(f); /* reserved */
675 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
676 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
681 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
685 mp4ff_atom_read_header(f, &atom_type, &header_size);
686 if (atom_type == ATOM_ESDS) {
693 static int32_t mp4ff_read_stsd(mp4ff_t * f)
696 uint8_t header_size = 0;
699 if (f->total_tracks == 0)
702 mp4ff_read_char(f); /* version */
703 mp4ff_read_int24(f); /* flags */
705 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
707 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
708 uint64_t skip = mp4ff_position(f);
710 uint8_t atom_type = 0;
711 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
714 if (atom_type == ATOM_MP4A) {
715 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
717 } else if (atom_type == ATOM_MP4V) {
718 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
719 } else if (atom_type == ATOM_MP4S) {
720 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
722 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
725 mp4ff_set_position(f, skip);
731 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
735 mp4ff_read_char(f); /* version */
736 mp4ff_read_int24(f); /* flags */
737 /* creation_time */ mp4ff_read_int32(f);
738 /* modification_time */ mp4ff_read_int32(f);
739 f->time_scale = mp4ff_read_int32(f);
740 f->duration = mp4ff_read_int32(f);
741 /* preferred_rate */ mp4ff_read_int32(f);
742 /*mp4ff_read_fixed32(f); */
743 /* preferred_volume */ mp4ff_read_int16(f);
744 /*mp4ff_read_fixed16(f); */
745 for (i = 0; i < 10; i++) {
746 /* reserved */ mp4ff_read_char(f);
748 for (i = 0; i < 9; i++) {
749 mp4ff_read_int32(f); /* matrix */
751 /* preview_time */ mp4ff_read_int32(f);
752 /* preview_duration */ mp4ff_read_int32(f);
753 /* poster_time */ mp4ff_read_int32(f);
754 /* selection_time */ mp4ff_read_int32(f);
755 /* selection_duration */ mp4ff_read_int32(f);
756 /* current_time */ mp4ff_read_int32(f);
757 /* next_track_id */ mp4ff_read_int32(f);
762 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
763 const char *value, int32_t len)
765 void *backup = (void *) tags->tags;
767 if (!item || (item && !*item) || !value)
770 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
771 (tags->count + 1) * sizeof (mp4ff_tag_t));
776 tags->tags[tags->count].item = para_strdup(item);
777 tags->tags[tags->count].len = len;
779 tags->tags[tags->count].value = para_malloc(len + 1);
780 memcpy(tags->tags[tags->count].value, value, len);
781 tags->tags[tags->count].value[len] = 0;
783 tags->tags[tags->count].value = para_strdup(value);
790 static const char *ID3v1GenreList[] = {
791 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
792 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
793 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
794 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
795 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
796 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
797 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
798 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
799 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
800 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
801 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
802 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
803 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
804 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
805 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
806 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
807 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
808 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
809 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
810 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
811 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
812 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
813 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
814 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
815 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
816 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
817 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
818 "Anime", "JPop", "SynthPop",
821 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
823 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
824 return ID3v1GenreList[idx - 1];
830 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
832 char *str = para_malloc(length + 1);
833 if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
841 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
843 static char *tag_names[] = {
844 "unknown", "title", "artist", "writer", "album",
845 "date", "tool", "comment", "genre", "track",
846 "disc", "compilation", "genre", "tempo", "cover",
847 "album_artist", "contentgroup", "lyrics", "description",
848 "network", "show", "episodename",
849 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
850 "sortwriter", "sortshow",
851 "season", "episode", "podcast"
886 case ATOM_COMPILATION:
898 case ATOM_ALBUM_ARTIST:
901 case ATOM_CONTENTGROUP:
907 case ATOM_DESCRIPTION:
916 case ATOM_EPISODENAME:
925 case ATOM_SORTARTIST:
928 case ATOM_SORTALBUMARTIST:
931 case ATOM_SORTWRITER:
951 *name = para_strdup(tag_names[tag_idx]);
955 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
959 uint8_t header_size = 0;
960 uint64_t subsize, sumsize;
969 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
970 mp4ff_set_position(f, destpos), sumsize += subsize
972 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
973 destpos = mp4ff_position(f) + subsize - header_size;
976 if (atom_type == ATOM_DATA) {
977 mp4ff_read_char(f); /* version */
978 mp4ff_read_int24(f); /* flags */
979 mp4ff_read_int32(f); /* reserved */
981 /* some need special attention */
982 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
983 if (subsize - header_size >= 8 + 2) {
984 uint16_t val = mp4ff_read_int16(f);
986 if (parent_atom_type == ATOM_TEMPO) {
991 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
993 const char *temp = mp4ff_meta_index_to_genre(val);
995 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1000 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1001 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1002 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1003 +sizeof (uint16_t) /* track / disc */
1004 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1005 uint16_t index, total;
1007 mp4ff_read_int16(f);
1008 index = mp4ff_read_int16(f);
1009 total = mp4ff_read_int16(f);
1010 if (parent_atom_type == ATOM_TRACK)
1011 mp4ff_read_int16(f);
1013 sprintf(temp, "%d", index);
1014 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1015 "track" : "disc", temp, -1);
1019 mp4ff_tag_add_field(& (f-> tags),
1020 parent_atom_type == ATOM_TRACK?
1021 "totaltracks" : "totaldiscs", temp, -1);
1027 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1028 len = (uint32_t) (subsize - (header_size + 8));
1030 } else if (atom_type == ATOM_NAME) {
1032 mp4ff_read_char(f); /* version */
1033 mp4ff_read_int24(f); /* flags */
1035 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1043 mp4ff_set_metadata_name(parent_atom_type, &name);
1045 mp4ff_tag_add_field(&(f->tags), name, data, len);
1054 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1059 if (f->total_tracks == 0)
1062 version = mp4ff_read_int32(f);
1064 mp4ff_read_int64(f); //creation-time
1065 mp4ff_read_int64(f); //modification-time
1066 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1067 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1068 } else //version == 0
1072 mp4ff_read_int32(f); //creation-time
1073 mp4ff_read_int32(f); //modification-time
1074 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1075 temp = mp4ff_read_int32(f);
1076 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1078 mp4ff_read_int16(f);
1079 mp4ff_read_int16(f);
1083 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1085 uint64_t subsize, sumsize = 0;
1087 uint8_t header_size = 0;
1089 while (sumsize < size) {
1090 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1093 mp4ff_parse_tag(f, atom_type,
1094 (uint32_t) (subsize - header_size));
1101 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1103 uint64_t subsize, sumsize = 0;
1105 uint8_t header_size = 0;
1107 mp4ff_read_char(f); /* version */
1108 mp4ff_read_int24(f); /* flags */
1110 while (sumsize < (size - (header_size + 4))) {
1111 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1112 if (subsize <= header_size + 4)
1114 if (atom_type == ATOM_ILST) {
1115 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1117 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1125 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1126 const uint8_t atom_type)
1128 uint64_t dest_position = mp4ff_position(f) + size - 8;
1129 if (atom_type == ATOM_STSZ) {
1130 /* sample size box */
1132 } else if (atom_type == ATOM_STTS) {
1133 /* time to sample box */
1135 } else if (atom_type == ATOM_CTTS) {
1136 /* composition offset box */
1138 } else if (atom_type == ATOM_STSC) {
1139 /* sample to chunk box */
1141 } else if (atom_type == ATOM_STCO) {
1142 /* chunk offset box */
1144 } else if (atom_type == ATOM_STSD) {
1145 /* sample description box */
1147 } else if (atom_type == ATOM_MVHD) {
1148 /* movie header box */
1150 } else if (atom_type == ATOM_MDHD) {
1153 } else if (atom_type == ATOM_META) {
1154 /* iTunes Metadata box */
1155 mp4ff_read_meta(f, size);
1158 mp4ff_set_position(f, dest_position);
1162 /* parse atoms that are sub atoms of other atoms */
1163 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1166 uint8_t atom_type = 0;
1167 uint64_t counted_size = 0;
1168 uint8_t header_size = 0;
1170 while (counted_size < total_size) {
1171 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1172 counted_size += size;
1174 /* check for end of file */
1178 /* we're starting to read a new track, update index,
1179 * so that all data and tables get written in the right place
1181 if (atom_type == ATOM_TRAK) {
1185 /* parse subatoms */
1186 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1187 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1188 } else if (atom_type < SUBATOMIC) {
1189 parse_sub_atoms(f, size - header_size, meta_only);
1191 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1198 /* parse root atoms */
1199 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1202 uint8_t atom_type = 0;
1203 uint8_t header_size = 0;
1206 f->stream->read_error = 0;
1209 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1210 f->file_size += size;
1211 f->last_atom = atom_type;
1213 if (atom_type == ATOM_MOOV && size > header_size) {
1214 f->moov_offset = mp4ff_position(f) - header_size;
1215 f->moov_size = size;
1218 /* parse subatoms */
1219 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1220 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1221 } else if (atom_type < SUBATOMIC) {
1222 parse_sub_atoms(f, size - header_size, meta_only);
1224 /* skip this atom */
1225 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1232 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1233 unsigned char **ppBuf, unsigned int *pBufSize)
1235 if (track >= f->total_tracks) {
1241 if (f->track[track]->decoderConfig == NULL
1242 || f->track[track]->decoderConfigLen == 0) {
1246 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1247 memcpy(*ppBuf, f->track[track]->decoderConfig,
1248 f->track[track]->decoderConfigLen);
1249 *pBufSize = f->track[track]->decoderConfigLen;
1253 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1255 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1269 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1273 for (i = 0; i < tags->count; i++) {
1274 free(tags->tags[i].item);
1275 free(tags->tags[i].value);
1284 void mp4ff_close(mp4ff_t * ff)
1288 for (i = 0; i < ff->total_tracks; i++) {
1290 free(ff->track[i]->stsz_table);
1291 free(ff->track[i]->stts_sample_count);
1292 free(ff->track[i]->stts_sample_delta);
1293 free(ff->track[i]->stsc_first_chunk);
1294 free(ff->track[i]->stsc_samples_per_chunk);
1295 free(ff->track[i]->stsc_sample_desc_index);
1296 free(ff->track[i]->stco_chunk_offset);
1297 free(ff->track[i]->decoderConfig);
1298 free(ff->track[i]->ctts_sample_count);
1299 free(ff->track[i]->ctts_sample_offset);
1304 mp4ff_tag_delete(&(ff->tags));
1308 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1309 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1311 int32_t total_entries = 0;
1312 int32_t chunk2entry;
1313 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1317 if (f->track[track] == NULL) {
1321 total_entries = f->track[track]->stsc_entry_count;
1328 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1329 *chunk = chunk2 - chunk1;
1330 range_samples = *chunk * chunk1samples;
1332 if (sample < total + range_samples)
1335 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1338 if (chunk2entry < total_entries) {
1340 total += range_samples;
1342 } while (chunk2entry < total_entries);
1345 *chunk = (sample - total) / chunk1samples + chunk1;
1349 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1354 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1355 const int32_t chunk)
1357 const mp4ff_track_t *p_track = f->track[track];
1359 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1360 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1362 } else if (p_track->stco_entry_count) {
1363 return p_track->stco_chunk_offset[chunk - 1];
1371 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1372 const int32_t chunk_sample, const int32_t sample)
1375 const mp4ff_track_t *p_track = f->track[track];
1377 if (p_track->stsz_sample_size) {
1378 return (sample - chunk_sample) * p_track->stsz_sample_size;
1380 if (sample >= p_track->stsz_sample_count)
1383 for (i = chunk_sample, total = 0; i < sample; i++) {
1384 total += p_track->stsz_table[i];
1390 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1391 const int32_t sample)
1393 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1395 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1397 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1398 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1399 track, chunk_sample, sample);
1400 return chunk_offset2;
1403 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1404 const int32_t sample)
1406 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1407 mp4ff_set_position(f, offset);
1410 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1412 const mp4ff_track_t *t = f->track[track];
1414 if (t->stsz_sample_size != 0)
1415 return t->stsz_sample_size;
1416 return t->stsz_table[sample];
1419 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1421 return f->track[track]->sampleRate;
1424 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1426 return f->track[track]->channelCount;
1429 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1434 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1435 total += f->track[track]->stts_sample_count[i];
1440 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1442 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1456 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1458 return f->tags.count;
1461 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1462 char **item, char **value)
1464 if (index >= f->tags.count) {
1469 *item = para_strdup(f->tags.tags[index].item);
1470 *value = para_strdup(f->tags.tags[index].value);
1475 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1478 uint32_t remaining = size;
1479 uint64_t atom_offset = base;
1484 mp4ff_set_position(f, atom_offset);
1488 atom_size = mp4ff_read_int32(f);
1489 if (atom_size > remaining || atom_size < 8)
1491 mp4ff_read_data(f, atom_name, 4);
1493 if (!memcmp(atom_name, name, 4)) {
1494 mp4ff_set_position(f, atom_offset);
1498 remaining -= atom_size;
1499 atom_offset += atom_size;
1503 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1504 const char *name, uint32_t extraheaders, const char *name_inside)
1506 uint64_t first_base = (uint64_t) (-1);
1507 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1509 uint64_t mybase = mp4ff_position(f);
1510 uint32_t mysize = mp4ff_read_int32(f);
1512 if (first_base == (uint64_t) (-1))
1513 first_base = mybase;
1515 if (mysize < 8 + extraheaders)
1518 if (find_atom (f, mybase + (8 + extraheaders),
1519 mysize - (8 + extraheaders), name_inside)) {
1520 mp4ff_set_position(f, mybase);
1524 if (size <= mysize) {
1531 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1533 mp4ff_set_position(f, first_base);
1546 #define stricmp strcasecmp
1548 static membuffer *membuffer_create(void)
1550 const unsigned initial_size = 256;
1552 membuffer *buf = para_malloc(sizeof (membuffer));
1553 buf->data = para_malloc(initial_size);
1555 buf->allocated = initial_size;
1556 buf->error = buf->data == 0 ? 1 : 0;
1561 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1563 unsigned dest_size = buf->written + bytes;
1567 if (dest_size > buf->allocated) {
1569 buf->allocated <<= 1;
1570 } while (dest_size > buf->allocated);
1573 void *newptr = realloc(buf->data, buf->allocated);
1585 memcpy((char *) buf->data + buf->written, ptr, bytes);
1586 buf->written += bytes;
1590 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1592 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1595 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1597 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1598 return membuffer_write(buf, temp, 2);
1601 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1603 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1604 (uint8_t) (data >> 8), (uint8_t) data };
1605 return membuffer_write(buf, temp, 4);
1608 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1609 uint32_t index, uint32_t total)
1611 membuffer_write_int32(buf,
1612 8 /*atom header */ + 8 /*data atom header */ +
1613 8 /*flags + reserved */ + 8 /*actual data */ );
1614 membuffer_write_atom_name(buf, name);
1615 membuffer_write_int32(buf,
1616 8 /*data atom header */ +
1617 8 /*flags + reserved */ + 8 /*actual data */ );
1618 membuffer_write_atom_name(buf, "data");
1619 membuffer_write_int32(buf, 0); //flags
1620 membuffer_write_int32(buf, 0); //reserved
1621 membuffer_write_int16(buf, 0);
1622 membuffer_write_int16(buf, (uint16_t) index); //track number
1623 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1624 membuffer_write_int16(buf, 0);
1627 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1630 membuffer_write_int32(buf,
1631 8 /*atom header */ + 8 /*data atom header */ +
1632 8 /*flags + reserved */ + 2 /*actual data */ );
1633 membuffer_write_atom_name(buf, name);
1634 membuffer_write_int32(buf,
1635 8 /*data atom header */ +
1636 8 /*flags + reserved */ + 2 /*actual data */ );
1637 membuffer_write_atom_name(buf, "data");
1638 membuffer_write_int32(buf, 0); //flags
1639 membuffer_write_int32(buf, 0); //reserved
1640 membuffer_write_int16(buf, value); //value
1643 static uint32_t myatoi(const char *param)
1645 return param ? atoi(param) : 0;
1648 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1651 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1652 if (!stricmp(genrestr, ID3v1GenreList[n]))
1663 static stdmeta_entry stdmetas[] = {
1664 {"\xA9" "nam", "title"},
1665 {"\xA9" "ART", "artist"},
1666 {"\xA9" "wrt", "writer"},
1667 {"\xA9" "alb", "album"},
1668 {"\xA9" "day", "date"},
1669 {"\xA9" "too", "tool"},
1670 {"\xA9" "cmt", "comment"},
1671 {"cpil", "compilation"},
1673 {"aART", "album_artist"},
1676 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1679 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1680 if (!stricmp(name, stdmetas[n].name))
1681 return stdmetas[n].atom;
1686 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1691 /* special check for compilation flag */
1692 if (strcmp(name, "cpil") == 0) {
1696 membuffer_write_int32(buf,
1697 8 /*atom header */ + 8 /*data atom header */ +
1698 8 /*flags + reserved */ + strlen(value));
1699 membuffer_write_atom_name(buf, name);
1700 membuffer_write_int32(buf,
1701 8 /*data atom header */ +
1702 8 /*flags + reserved */ + strlen(value));
1703 membuffer_write_atom_name(buf, "data");
1704 membuffer_write_int32(buf, flags); //flags
1705 membuffer_write_int32(buf, 0); //reserved
1706 membuffer_write(buf, value, strlen(value));
1709 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1712 membuffer_write_int32(buf,
1713 8 /*atom header */ +
1714 0x1C /*weirdo itunes atom */ +
1715 12 /*name atom header */ + strlen(name) +
1716 16 /*data atom header + flags */ + strlen(value));
1717 membuffer_write_atom_name(buf, "----");
1718 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1719 membuffer_write_atom_name(buf, "mean");
1720 membuffer_write_int32(buf, 0);
1721 membuffer_write(buf, "com.apple.iTunes", 16);
1722 membuffer_write_int32(buf, 12 + strlen(name));
1723 membuffer_write_atom_name(buf, "name");
1724 membuffer_write_int32(buf, 0);
1725 membuffer_write(buf, name, strlen(name));
1726 membuffer_write_int32(buf,
1727 8 /*data atom header */ +
1728 8 /*flags + reserved */ + strlen(value));
1729 membuffer_write_atom_name(buf, "data");
1730 membuffer_write_int32(buf, 1); //flags
1731 membuffer_write_int32(buf, 0); //reserved
1732 membuffer_write(buf, value, strlen(value));
1735 static unsigned membuffer_error(const membuffer * buf)
1740 static void membuffer_free(membuffer * buf)
1746 static unsigned membuffer_get_size(const membuffer * buf)
1748 return buf->written;
1751 static void *membuffer_detach(membuffer * buf)
1758 ret = realloc(buf->data, buf->written);
1769 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1770 uint32_t * out_size)
1772 membuffer *buf = membuffer_create();
1774 char *mask = para_calloc(data->count);
1776 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1777 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1778 const char *genre_ptr = 0, *tempo_ptr = 0;
1779 for (metaptr = 0; metaptr < data->count; metaptr++) {
1780 mp4ff_tag_t *tag = &data->tags[metaptr];
1781 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1782 if (tracknumber_ptr == 0)
1783 tracknumber_ptr = tag->value;
1785 } else if (!stricmp(tag->item, "totaltracks")) {
1786 if (totaltracks_ptr == 0)
1787 totaltracks_ptr = tag->value;
1789 } else if (!stricmp(tag->item, "discnumber")
1790 || !stricmp(tag->item, "disc")) {
1791 if (discnumber_ptr == 0)
1792 discnumber_ptr = tag->value;
1794 } else if (!stricmp(tag->item, "totaldiscs")) {
1795 if (totaldiscs_ptr == 0)
1796 totaldiscs_ptr = tag->value;
1798 } else if (!stricmp(tag->item, "genre")) {
1800 genre_ptr = tag->value;
1802 } else if (!stricmp(tag->item, "tempo")) {
1804 tempo_ptr = tag->value;
1810 if (tracknumber_ptr)
1811 membuffer_write_track_tag(buf, "trkn",
1812 myatoi(tracknumber_ptr),
1813 myatoi(totaltracks_ptr));
1815 membuffer_write_track_tag(buf, "disk",
1816 myatoi(discnumber_ptr),
1817 myatoi(totaldiscs_ptr));
1819 membuffer_write_int16_tag(buf, "tmpo",
1820 (uint16_t) myatoi(tempo_ptr));
1823 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1825 membuffer_write_std_tag(buf, "©gen",
1828 membuffer_write_int16_tag(buf, "gnre",
1833 for (metaptr = 0; metaptr < data->count; metaptr++) {
1834 if (!mask[metaptr]) {
1835 mp4ff_tag_t *tag = &data->tags[metaptr];
1836 const char *std_meta_atom = find_standard_meta(tag->item);
1837 if (std_meta_atom) {
1838 membuffer_write_std_tag(buf, std_meta_atom,
1841 membuffer_write_custom_tag(buf, tag->item,
1849 if (membuffer_error(buf)) {
1850 membuffer_free(buf);
1854 *out_size = membuffer_get_size(buf);
1855 *out_buffer = membuffer_detach(buf);
1856 membuffer_free(buf);
1861 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1864 membuffer_write_int32(buf, size + 8);
1865 membuffer_write_atom_name(buf, name);
1866 membuffer_write(buf, data, size);
1869 static void *membuffer_get_ptr(const membuffer * buf)
1874 static void membuffer_set_error(membuffer * buf)
1879 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1885 oldsize = membuffer_get_size(buf);
1886 if (membuffer_write(buf, 0, bytes) != bytes)
1889 bufptr = membuffer_get_ptr(buf);
1893 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1895 membuffer_set_error(buf);
1902 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1903 uint32_t * out_size)
1909 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1912 buf = membuffer_create();
1914 membuffer_write_int32(buf, 0);
1915 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1918 *out_size = membuffer_get_size(buf);
1919 *out_buffer = membuffer_detach(buf);
1920 membuffer_free(buf);
1924 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1925 uint32_t * out_size)
1931 if (!create_meta(data, &meta_buffer, &meta_size))
1934 buf = membuffer_create();
1936 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1940 *out_size = membuffer_get_size(buf);
1941 *out_buffer = membuffer_detach(buf);
1942 membuffer_free(buf);
1946 static uint32_t fix_byte_order_32(uint32_t src)
1949 uint32_t a, b, c, d;
1952 memcpy(data, &src, sizeof (src));
1953 a = (uint8_t) data[0];
1954 b = (uint8_t) data[1];
1955 c = (uint8_t) data[2];
1956 d = (uint8_t) data[3];
1958 result = (a << 24) | (b << 16) | (c << 8) | d;
1959 return (uint32_t) result;
1962 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1963 void **out_buffer, uint32_t * out_size)
1965 uint64_t total_base = f->moov_offset + 8;
1966 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1968 uint64_t udta_offset, meta_offset, ilst_offset;
1969 uint32_t udta_size, meta_size, ilst_size;
1971 uint32_t new_ilst_size;
1972 void *new_ilst_buffer;
1977 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1979 void *new_udta_buffer;
1980 uint32_t new_udta_size;
1981 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1984 buf = membuffer_create();
1985 mp4ff_set_position(f, total_base);
1986 membuffer_transfer_from_file(buf, f, total_size);
1988 membuffer_write_atom(buf, "udta", new_udta_size,
1991 free(new_udta_buffer);
1993 *out_size = membuffer_get_size(buf);
1994 *out_buffer = membuffer_detach(buf);
1995 membuffer_free(buf);
1998 udta_offset = mp4ff_position(f);
1999 udta_size = mp4ff_read_int32(f);
2000 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2002 void *new_meta_buffer;
2003 uint32_t new_meta_size;
2004 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2007 buf = membuffer_create();
2008 mp4ff_set_position(f, total_base);
2009 membuffer_transfer_from_file(buf, f,
2010 (uint32_t)(udta_offset - total_base));
2012 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2013 membuffer_write_atom_name(buf, "udta");
2014 membuffer_transfer_from_file(buf, f, udta_size);
2016 membuffer_write_atom(buf, "meta", new_meta_size,
2018 free(new_meta_buffer);
2020 *out_size = membuffer_get_size(buf);
2021 *out_buffer = membuffer_detach(buf);
2022 membuffer_free(buf);
2025 meta_offset = mp4ff_position(f);
2026 meta_size = mp4ff_read_int32(f);
2027 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2028 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2029 ilst_offset = mp4ff_position(f);
2030 ilst_size = mp4ff_read_int32(f);
2032 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2035 size_delta = new_ilst_size - (ilst_size - 8);
2037 *out_size = total_size + size_delta;
2038 *out_buffer = para_malloc(*out_size);
2039 p_out = (uint8_t *) * out_buffer;
2041 mp4ff_set_position(f, total_base);
2042 mp4ff_read_data(f, p_out,
2043 (uint32_t) (udta_offset - total_base));
2044 p_out += (uint32_t) (udta_offset - total_base);
2045 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2047 mp4ff_read_data(f, p_out, 4);
2049 mp4ff_read_data(f, p_out,
2050 (uint32_t) (meta_offset - udta_offset - 8));
2051 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2052 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2054 mp4ff_read_data(f, p_out, 4);
2056 mp4ff_read_data(f, p_out,
2057 (uint32_t) (ilst_offset - meta_offset - 8));
2058 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2059 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2061 mp4ff_read_data(f, p_out, 4);
2064 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2065 p_out += new_ilst_size;
2067 mp4ff_set_position(f, ilst_offset + ilst_size);
2068 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2069 - (ilst_offset - total_base) - ilst_size));
2071 free(new_ilst_buffer);
2076 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2080 result = f->stream->write(f->stream->user_data, data, size);
2082 f->current_position += size;
2087 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2090 uint32_t a, b, c, d;
2093 *(uint32_t *) temp = data;
2094 a = (uint8_t) temp[0];
2095 b = (uint8_t) temp[1];
2096 c = (uint8_t) temp[2];
2097 d = (uint8_t) temp[3];
2099 result = (a << 24) | (b << 16) | (c << 8) | d;
2101 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2104 static int32_t mp4ff_truncate(mp4ff_t * f)
2106 return f->stream->truncate(f->stream->user_data);
2109 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2111 void *new_moov_data;
2112 uint32_t new_moov_size;
2114 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2116 mp4ff_set_position(ff, 0);
2120 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2125 /* copy moov atom to end of the file */
2126 if (ff->last_atom != ATOM_MOOV) {
2127 char *free_data = "free";
2129 /* rename old moov to free */
2130 mp4ff_set_position(ff, ff->moov_offset + 4);
2131 mp4ff_write_data(ff, free_data, 4);
2133 mp4ff_set_position(ff, ff->file_size);
2134 mp4ff_write_int32(ff, new_moov_size + 8);
2135 mp4ff_write_data(ff, "moov", 4);
2136 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2138 mp4ff_set_position(ff, ff->moov_offset);
2139 mp4ff_write_int32(ff, new_moov_size + 8);
2140 mp4ff_write_data(ff, "moov", 4);
2141 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2150 /* find a metadata item by name */
2151 /* returns 0 if item found, 1 if no such item */
2152 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2157 for (i = 0; i < f->tags.count; i++) {
2158 if (!stricmp(f->tags.tags[i].item, item)) {
2159 *value = para_strdup(f->tags.tags[i].value);
2170 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2172 return mp4ff_meta_find_by_name(f, "artist", value);
2175 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2177 return mp4ff_meta_find_by_name(f, "title", value);
2180 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2182 return mp4ff_meta_find_by_name(f, "date", value);
2185 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2187 return mp4ff_meta_find_by_name(f, "album", value);
2190 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2192 return mp4ff_meta_find_by_name(f, "comment", value);