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_NAME) {
977 mp4ff_read_char(f); /* version */
978 mp4ff_read_int24(f); /* flags */
980 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
983 if (atom_type != ATOM_DATA)
985 mp4ff_read_char(f); /* version */
986 mp4ff_read_int24(f); /* flags */
987 mp4ff_read_int32(f); /* reserved */
989 /* some need special attention */
990 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
991 if (subsize - header_size >= 8 + 2) {
992 uint16_t val = mp4ff_read_int16(f);
994 if (parent_atom_type == ATOM_TEMPO) {
996 sprintf(temp, "%.5u BPM", val);
997 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
999 const char *temp = mp4ff_meta_index_to_genre(val);
1001 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1005 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1006 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1007 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1008 +sizeof (uint16_t) /* track / disc */
1009 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1010 uint16_t index, total;
1012 mp4ff_read_int16(f);
1013 index = mp4ff_read_int16(f);
1014 total = mp4ff_read_int16(f);
1015 if (parent_atom_type == ATOM_TRACK)
1016 mp4ff_read_int16(f);
1018 sprintf(temp, "%d", index);
1019 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1020 "track" : "disc", temp, -1);
1024 mp4ff_tag_add_field(& (f-> tags),
1025 parent_atom_type == ATOM_TRACK?
1026 "totaltracks" : "totaldiscs", temp, -1);
1032 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1033 len = (uint32_t) (subsize - (header_size + 8));
1039 mp4ff_set_metadata_name(parent_atom_type, &name);
1041 mp4ff_tag_add_field(&(f->tags), name, data, len);
1050 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1055 if (f->total_tracks == 0)
1058 version = mp4ff_read_int32(f);
1060 mp4ff_read_int64(f); //creation-time
1061 mp4ff_read_int64(f); //modification-time
1062 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1063 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1064 } else //version == 0
1068 mp4ff_read_int32(f); //creation-time
1069 mp4ff_read_int32(f); //modification-time
1070 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1071 temp = mp4ff_read_int32(f);
1072 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1074 mp4ff_read_int16(f);
1075 mp4ff_read_int16(f);
1079 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1081 uint64_t subsize, sumsize = 0;
1083 uint8_t header_size = 0;
1085 while (sumsize < size) {
1086 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1089 mp4ff_parse_tag(f, atom_type,
1090 (uint32_t) (subsize - header_size));
1097 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1099 uint64_t subsize, sumsize = 0;
1101 uint8_t header_size = 0;
1103 mp4ff_read_char(f); /* version */
1104 mp4ff_read_int24(f); /* flags */
1106 while (sumsize < (size - (header_size + 4))) {
1107 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1108 if (subsize <= header_size + 4)
1110 if (atom_type == ATOM_ILST) {
1111 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1113 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1121 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1122 const uint8_t atom_type)
1124 uint64_t dest_position = mp4ff_position(f) + size - 8;
1125 if (atom_type == ATOM_STSZ) {
1126 /* sample size box */
1128 } else if (atom_type == ATOM_STTS) {
1129 /* time to sample box */
1131 } else if (atom_type == ATOM_CTTS) {
1132 /* composition offset box */
1134 } else if (atom_type == ATOM_STSC) {
1135 /* sample to chunk box */
1137 } else if (atom_type == ATOM_STCO) {
1138 /* chunk offset box */
1140 } else if (atom_type == ATOM_STSD) {
1141 /* sample description box */
1143 } else if (atom_type == ATOM_MVHD) {
1144 /* movie header box */
1146 } else if (atom_type == ATOM_MDHD) {
1149 } else if (atom_type == ATOM_META) {
1150 /* iTunes Metadata box */
1151 mp4ff_read_meta(f, size);
1154 mp4ff_set_position(f, dest_position);
1158 /* parse atoms that are sub atoms of other atoms */
1159 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1162 uint8_t atom_type = 0;
1163 uint64_t counted_size = 0;
1164 uint8_t header_size = 0;
1166 while (counted_size < total_size) {
1167 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1168 counted_size += size;
1170 /* check for end of file */
1174 /* we're starting to read a new track, update index,
1175 * so that all data and tables get written in the right place
1177 if (atom_type == ATOM_TRAK) {
1181 /* parse subatoms */
1182 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1183 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1184 } else if (atom_type < SUBATOMIC) {
1185 parse_sub_atoms(f, size - header_size, meta_only);
1187 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1194 /* parse root atoms */
1195 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1198 uint8_t atom_type = 0;
1199 uint8_t header_size = 0;
1202 f->stream->read_error = 0;
1205 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1206 f->file_size += size;
1207 f->last_atom = atom_type;
1209 if (atom_type == ATOM_MOOV && size > header_size) {
1210 f->moov_offset = mp4ff_position(f) - header_size;
1211 f->moov_size = size;
1214 /* parse subatoms */
1215 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1216 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1217 } else if (atom_type < SUBATOMIC) {
1218 parse_sub_atoms(f, size - header_size, meta_only);
1220 /* skip this atom */
1221 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1228 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1229 unsigned char **ppBuf, unsigned int *pBufSize)
1231 if (track >= f->total_tracks) {
1237 if (f->track[track]->decoderConfig == NULL
1238 || f->track[track]->decoderConfigLen == 0) {
1242 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1243 memcpy(*ppBuf, f->track[track]->decoderConfig,
1244 f->track[track]->decoderConfigLen);
1245 *pBufSize = f->track[track]->decoderConfigLen;
1249 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1251 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1265 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1269 for (i = 0; i < tags->count; i++) {
1270 free(tags->tags[i].item);
1271 free(tags->tags[i].value);
1280 void mp4ff_close(mp4ff_t * ff)
1284 for (i = 0; i < ff->total_tracks; i++) {
1286 free(ff->track[i]->stsz_table);
1287 free(ff->track[i]->stts_sample_count);
1288 free(ff->track[i]->stts_sample_delta);
1289 free(ff->track[i]->stsc_first_chunk);
1290 free(ff->track[i]->stsc_samples_per_chunk);
1291 free(ff->track[i]->stsc_sample_desc_index);
1292 free(ff->track[i]->stco_chunk_offset);
1293 free(ff->track[i]->decoderConfig);
1294 free(ff->track[i]->ctts_sample_count);
1295 free(ff->track[i]->ctts_sample_offset);
1300 mp4ff_tag_delete(&(ff->tags));
1304 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1305 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1307 int32_t total_entries = 0;
1308 int32_t chunk2entry;
1309 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1313 if (f->track[track] == NULL) {
1317 total_entries = f->track[track]->stsc_entry_count;
1324 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1325 *chunk = chunk2 - chunk1;
1326 range_samples = *chunk * chunk1samples;
1328 if (sample < total + range_samples)
1331 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1334 if (chunk2entry < total_entries) {
1336 total += range_samples;
1338 } while (chunk2entry < total_entries);
1341 *chunk = (sample - total) / chunk1samples + chunk1;
1345 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1350 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1351 const int32_t chunk)
1353 const mp4ff_track_t *p_track = f->track[track];
1355 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1356 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1358 } else if (p_track->stco_entry_count) {
1359 return p_track->stco_chunk_offset[chunk - 1];
1367 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1368 const int32_t chunk_sample, const int32_t sample)
1371 const mp4ff_track_t *p_track = f->track[track];
1373 if (p_track->stsz_sample_size) {
1374 return (sample - chunk_sample) * p_track->stsz_sample_size;
1376 if (sample >= p_track->stsz_sample_count)
1379 for (i = chunk_sample, total = 0; i < sample; i++) {
1380 total += p_track->stsz_table[i];
1386 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1387 const int32_t sample)
1389 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1391 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1393 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1394 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1395 track, chunk_sample, sample);
1396 return chunk_offset2;
1399 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1400 const int32_t sample)
1402 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1403 mp4ff_set_position(f, offset);
1406 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1408 const mp4ff_track_t *t = f->track[track];
1410 if (t->stsz_sample_size != 0)
1411 return t->stsz_sample_size;
1412 return t->stsz_table[sample];
1415 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1417 return f->track[track]->sampleRate;
1420 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1422 return f->track[track]->channelCount;
1425 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1430 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1431 total += f->track[track]->stts_sample_count[i];
1436 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1438 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1452 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1454 return f->tags.count;
1457 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1458 char **item, char **value)
1460 if (index >= f->tags.count) {
1465 *item = para_strdup(f->tags.tags[index].item);
1466 *value = para_strdup(f->tags.tags[index].value);
1471 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1474 uint32_t remaining = size;
1475 uint64_t atom_offset = base;
1480 mp4ff_set_position(f, atom_offset);
1484 atom_size = mp4ff_read_int32(f);
1485 if (atom_size > remaining || atom_size < 8)
1487 mp4ff_read_data(f, atom_name, 4);
1489 if (!memcmp(atom_name, name, 4)) {
1490 mp4ff_set_position(f, atom_offset);
1494 remaining -= atom_size;
1495 atom_offset += atom_size;
1499 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1500 const char *name, uint32_t extraheaders, const char *name_inside)
1502 uint64_t first_base = (uint64_t) (-1);
1503 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1505 uint64_t mybase = mp4ff_position(f);
1506 uint32_t mysize = mp4ff_read_int32(f);
1508 if (first_base == (uint64_t) (-1))
1509 first_base = mybase;
1511 if (mysize < 8 + extraheaders)
1514 if (find_atom (f, mybase + (8 + extraheaders),
1515 mysize - (8 + extraheaders), name_inside)) {
1516 mp4ff_set_position(f, mybase);
1520 if (size <= mysize) {
1527 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1529 mp4ff_set_position(f, first_base);
1542 #define stricmp strcasecmp
1544 static membuffer *membuffer_create(void)
1546 const unsigned initial_size = 256;
1548 membuffer *buf = para_malloc(sizeof (membuffer));
1549 buf->data = para_malloc(initial_size);
1551 buf->allocated = initial_size;
1552 buf->error = buf->data == 0 ? 1 : 0;
1557 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1559 unsigned dest_size = buf->written + bytes;
1563 if (dest_size > buf->allocated) {
1565 buf->allocated <<= 1;
1566 } while (dest_size > buf->allocated);
1569 void *newptr = realloc(buf->data, buf->allocated);
1581 memcpy((char *) buf->data + buf->written, ptr, bytes);
1582 buf->written += bytes;
1586 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1588 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1591 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1593 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1594 return membuffer_write(buf, temp, 2);
1597 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1599 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1600 (uint8_t) (data >> 8), (uint8_t) data };
1601 return membuffer_write(buf, temp, 4);
1604 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1605 uint32_t index, uint32_t total)
1607 membuffer_write_int32(buf,
1608 8 /*atom header */ + 8 /*data atom header */ +
1609 8 /*flags + reserved */ + 8 /*actual data */ );
1610 membuffer_write_atom_name(buf, name);
1611 membuffer_write_int32(buf,
1612 8 /*data atom header */ +
1613 8 /*flags + reserved */ + 8 /*actual data */ );
1614 membuffer_write_atom_name(buf, "data");
1615 membuffer_write_int32(buf, 0); //flags
1616 membuffer_write_int32(buf, 0); //reserved
1617 membuffer_write_int16(buf, 0);
1618 membuffer_write_int16(buf, (uint16_t) index); //track number
1619 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1620 membuffer_write_int16(buf, 0);
1623 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1626 membuffer_write_int32(buf,
1627 8 /*atom header */ + 8 /*data atom header */ +
1628 8 /*flags + reserved */ + 2 /*actual data */ );
1629 membuffer_write_atom_name(buf, name);
1630 membuffer_write_int32(buf,
1631 8 /*data atom header */ +
1632 8 /*flags + reserved */ + 2 /*actual data */ );
1633 membuffer_write_atom_name(buf, "data");
1634 membuffer_write_int32(buf, 0); //flags
1635 membuffer_write_int32(buf, 0); //reserved
1636 membuffer_write_int16(buf, value); //value
1639 static uint32_t myatoi(const char *param)
1641 return param ? atoi(param) : 0;
1644 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1647 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1648 if (!stricmp(genrestr, ID3v1GenreList[n]))
1659 static stdmeta_entry stdmetas[] = {
1660 {"\xA9" "nam", "title"},
1661 {"\xA9" "ART", "artist"},
1662 {"\xA9" "wrt", "writer"},
1663 {"\xA9" "alb", "album"},
1664 {"\xA9" "day", "date"},
1665 {"\xA9" "too", "tool"},
1666 {"\xA9" "cmt", "comment"},
1667 {"cpil", "compilation"},
1669 {"aART", "album_artist"},
1672 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1675 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1676 if (!stricmp(name, stdmetas[n].name))
1677 return stdmetas[n].atom;
1682 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1687 /* special check for compilation flag */
1688 if (strcmp(name, "cpil") == 0) {
1692 membuffer_write_int32(buf,
1693 8 /*atom header */ + 8 /*data atom header */ +
1694 8 /*flags + reserved */ + strlen(value));
1695 membuffer_write_atom_name(buf, name);
1696 membuffer_write_int32(buf,
1697 8 /*data atom header */ +
1698 8 /*flags + reserved */ + strlen(value));
1699 membuffer_write_atom_name(buf, "data");
1700 membuffer_write_int32(buf, flags); //flags
1701 membuffer_write_int32(buf, 0); //reserved
1702 membuffer_write(buf, value, strlen(value));
1705 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1708 membuffer_write_int32(buf,
1709 8 /*atom header */ +
1710 0x1C /*weirdo itunes atom */ +
1711 12 /*name atom header */ + strlen(name) +
1712 16 /*data atom header + flags */ + strlen(value));
1713 membuffer_write_atom_name(buf, "----");
1714 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1715 membuffer_write_atom_name(buf, "mean");
1716 membuffer_write_int32(buf, 0);
1717 membuffer_write(buf, "com.apple.iTunes", 16);
1718 membuffer_write_int32(buf, 12 + strlen(name));
1719 membuffer_write_atom_name(buf, "name");
1720 membuffer_write_int32(buf, 0);
1721 membuffer_write(buf, name, strlen(name));
1722 membuffer_write_int32(buf,
1723 8 /*data atom header */ +
1724 8 /*flags + reserved */ + strlen(value));
1725 membuffer_write_atom_name(buf, "data");
1726 membuffer_write_int32(buf, 1); //flags
1727 membuffer_write_int32(buf, 0); //reserved
1728 membuffer_write(buf, value, strlen(value));
1731 static unsigned membuffer_error(const membuffer * buf)
1736 static void membuffer_free(membuffer * buf)
1742 static unsigned membuffer_get_size(const membuffer * buf)
1744 return buf->written;
1747 static void *membuffer_detach(membuffer * buf)
1754 ret = realloc(buf->data, buf->written);
1765 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1766 uint32_t * out_size)
1768 membuffer *buf = membuffer_create();
1770 char *mask = para_calloc(data->count);
1772 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1773 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1774 const char *genre_ptr = 0, *tempo_ptr = 0;
1775 for (metaptr = 0; metaptr < data->count; metaptr++) {
1776 mp4ff_tag_t *tag = &data->tags[metaptr];
1777 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1778 if (tracknumber_ptr == 0)
1779 tracknumber_ptr = tag->value;
1781 } else if (!stricmp(tag->item, "totaltracks")) {
1782 if (totaltracks_ptr == 0)
1783 totaltracks_ptr = tag->value;
1785 } else if (!stricmp(tag->item, "discnumber")
1786 || !stricmp(tag->item, "disc")) {
1787 if (discnumber_ptr == 0)
1788 discnumber_ptr = tag->value;
1790 } else if (!stricmp(tag->item, "totaldiscs")) {
1791 if (totaldiscs_ptr == 0)
1792 totaldiscs_ptr = tag->value;
1794 } else if (!stricmp(tag->item, "genre")) {
1796 genre_ptr = tag->value;
1798 } else if (!stricmp(tag->item, "tempo")) {
1800 tempo_ptr = tag->value;
1806 if (tracknumber_ptr)
1807 membuffer_write_track_tag(buf, "trkn",
1808 myatoi(tracknumber_ptr),
1809 myatoi(totaltracks_ptr));
1811 membuffer_write_track_tag(buf, "disk",
1812 myatoi(discnumber_ptr),
1813 myatoi(totaldiscs_ptr));
1815 membuffer_write_int16_tag(buf, "tmpo",
1816 (uint16_t) myatoi(tempo_ptr));
1819 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1821 membuffer_write_std_tag(buf, "©gen",
1824 membuffer_write_int16_tag(buf, "gnre",
1829 for (metaptr = 0; metaptr < data->count; metaptr++) {
1830 if (!mask[metaptr]) {
1831 mp4ff_tag_t *tag = &data->tags[metaptr];
1832 const char *std_meta_atom = find_standard_meta(tag->item);
1833 if (std_meta_atom) {
1834 membuffer_write_std_tag(buf, std_meta_atom,
1837 membuffer_write_custom_tag(buf, tag->item,
1845 if (membuffer_error(buf)) {
1846 membuffer_free(buf);
1850 *out_size = membuffer_get_size(buf);
1851 *out_buffer = membuffer_detach(buf);
1852 membuffer_free(buf);
1857 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1860 membuffer_write_int32(buf, size + 8);
1861 membuffer_write_atom_name(buf, name);
1862 membuffer_write(buf, data, size);
1865 static void *membuffer_get_ptr(const membuffer * buf)
1870 static void membuffer_set_error(membuffer * buf)
1875 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1881 oldsize = membuffer_get_size(buf);
1882 if (membuffer_write(buf, 0, bytes) != bytes)
1885 bufptr = membuffer_get_ptr(buf);
1889 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1891 membuffer_set_error(buf);
1898 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1899 uint32_t * out_size)
1905 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1908 buf = membuffer_create();
1910 membuffer_write_int32(buf, 0);
1911 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1914 *out_size = membuffer_get_size(buf);
1915 *out_buffer = membuffer_detach(buf);
1916 membuffer_free(buf);
1920 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1921 uint32_t * out_size)
1927 if (!create_meta(data, &meta_buffer, &meta_size))
1930 buf = membuffer_create();
1932 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1936 *out_size = membuffer_get_size(buf);
1937 *out_buffer = membuffer_detach(buf);
1938 membuffer_free(buf);
1942 static uint32_t fix_byte_order_32(uint32_t src)
1945 uint32_t a, b, c, d;
1948 memcpy(data, &src, sizeof (src));
1949 a = (uint8_t) data[0];
1950 b = (uint8_t) data[1];
1951 c = (uint8_t) data[2];
1952 d = (uint8_t) data[3];
1954 result = (a << 24) | (b << 16) | (c << 8) | d;
1955 return (uint32_t) result;
1958 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1959 void **out_buffer, uint32_t * out_size)
1961 uint64_t total_base = f->moov_offset + 8;
1962 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1964 uint64_t udta_offset, meta_offset, ilst_offset;
1965 uint32_t udta_size, meta_size, ilst_size;
1967 uint32_t new_ilst_size;
1968 void *new_ilst_buffer;
1973 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1975 void *new_udta_buffer;
1976 uint32_t new_udta_size;
1977 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1980 buf = membuffer_create();
1981 mp4ff_set_position(f, total_base);
1982 membuffer_transfer_from_file(buf, f, total_size);
1984 membuffer_write_atom(buf, "udta", new_udta_size,
1987 free(new_udta_buffer);
1989 *out_size = membuffer_get_size(buf);
1990 *out_buffer = membuffer_detach(buf);
1991 membuffer_free(buf);
1994 udta_offset = mp4ff_position(f);
1995 udta_size = mp4ff_read_int32(f);
1996 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1998 void *new_meta_buffer;
1999 uint32_t new_meta_size;
2000 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2003 buf = membuffer_create();
2004 mp4ff_set_position(f, total_base);
2005 membuffer_transfer_from_file(buf, f,
2006 (uint32_t)(udta_offset - total_base));
2008 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2009 membuffer_write_atom_name(buf, "udta");
2010 membuffer_transfer_from_file(buf, f, udta_size);
2012 membuffer_write_atom(buf, "meta", new_meta_size,
2014 free(new_meta_buffer);
2016 *out_size = membuffer_get_size(buf);
2017 *out_buffer = membuffer_detach(buf);
2018 membuffer_free(buf);
2021 meta_offset = mp4ff_position(f);
2022 meta_size = mp4ff_read_int32(f);
2023 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2024 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2025 ilst_offset = mp4ff_position(f);
2026 ilst_size = mp4ff_read_int32(f);
2028 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2031 size_delta = new_ilst_size - (ilst_size - 8);
2033 *out_size = total_size + size_delta;
2034 *out_buffer = para_malloc(*out_size);
2035 p_out = (uint8_t *) * out_buffer;
2037 mp4ff_set_position(f, total_base);
2038 mp4ff_read_data(f, p_out,
2039 (uint32_t) (udta_offset - total_base));
2040 p_out += (uint32_t) (udta_offset - total_base);
2041 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2043 mp4ff_read_data(f, p_out, 4);
2045 mp4ff_read_data(f, p_out,
2046 (uint32_t) (meta_offset - udta_offset - 8));
2047 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2048 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2050 mp4ff_read_data(f, p_out, 4);
2052 mp4ff_read_data(f, p_out,
2053 (uint32_t) (ilst_offset - meta_offset - 8));
2054 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2055 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2057 mp4ff_read_data(f, p_out, 4);
2060 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2061 p_out += new_ilst_size;
2063 mp4ff_set_position(f, ilst_offset + ilst_size);
2064 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2065 - (ilst_offset - total_base) - ilst_size));
2067 free(new_ilst_buffer);
2072 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2076 result = f->stream->write(f->stream->user_data, data, size);
2078 f->current_position += size;
2083 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2086 uint32_t a, b, c, d;
2089 *(uint32_t *) temp = data;
2090 a = (uint8_t) temp[0];
2091 b = (uint8_t) temp[1];
2092 c = (uint8_t) temp[2];
2093 d = (uint8_t) temp[3];
2095 result = (a << 24) | (b << 16) | (c << 8) | d;
2097 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2100 static int32_t mp4ff_truncate(mp4ff_t * f)
2102 return f->stream->truncate(f->stream->user_data);
2105 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2107 void *new_moov_data;
2108 uint32_t new_moov_size;
2110 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2112 mp4ff_set_position(ff, 0);
2116 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2121 /* copy moov atom to end of the file */
2122 if (ff->last_atom != ATOM_MOOV) {
2123 char *free_data = "free";
2125 /* rename old moov to free */
2126 mp4ff_set_position(ff, ff->moov_offset + 4);
2127 mp4ff_write_data(ff, free_data, 4);
2129 mp4ff_set_position(ff, ff->file_size);
2130 mp4ff_write_int32(ff, new_moov_size + 8);
2131 mp4ff_write_data(ff, "moov", 4);
2132 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2134 mp4ff_set_position(ff, ff->moov_offset);
2135 mp4ff_write_int32(ff, new_moov_size + 8);
2136 mp4ff_write_data(ff, "moov", 4);
2137 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2146 /* find a metadata item by name */
2147 /* returns 0 if item found, 1 if no such item */
2148 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2153 for (i = 0; i < f->tags.count; i++) {
2154 if (!stricmp(f->tags.tags[i].item, item)) {
2155 *value = para_strdup(f->tags.tags[i].value);
2166 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2168 return mp4ff_meta_find_by_name(f, "artist", value);
2171 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2173 return mp4ff_meta_find_by_name(f, "title", value);
2176 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2178 return mp4ff_meta_find_by_name(f, "date", value);
2181 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2183 return mp4ff_meta_find_by_name(f, "album", value);
2186 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2188 return mp4ff_meta_find_by_name(f, "comment", value);