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 = 0;
966 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
968 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
969 destpos = mp4ff_position(f) + subsize - header_size;
972 if (atom_type == ATOM_DATA) {
973 mp4ff_read_char(f); /* version */
974 mp4ff_read_int24(f); /* flags */
975 mp4ff_read_int32(f); /* reserved */
977 /* some need special attention */
978 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
979 if (subsize - header_size >= 8 + 2) {
980 uint16_t val = mp4ff_read_int16(f);
982 if (parent_atom_type == ATOM_TEMPO) {
987 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
989 const char *temp = mp4ff_meta_index_to_genre(val);
991 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
996 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
997 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
998 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
999 +sizeof (uint16_t) /* track / disc */
1000 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1001 uint16_t index, total;
1003 mp4ff_read_int16(f);
1004 index = mp4ff_read_int16(f);
1005 total = mp4ff_read_int16(f);
1006 if (parent_atom_type == ATOM_TRACK)
1007 mp4ff_read_int16(f);
1009 sprintf(temp, "%d", index);
1010 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1011 "track" : "disc", temp, -1);
1015 mp4ff_tag_add_field(& (f-> tags),
1016 parent_atom_type == ATOM_TRACK?
1017 "totaltracks" : "totaldiscs", temp, -1);
1023 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1024 len = (uint32_t) (subsize - (header_size + 8));
1026 } else if (atom_type == ATOM_NAME) {
1028 mp4ff_read_char(f); /* version */
1029 mp4ff_read_int24(f); /* flags */
1031 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1034 mp4ff_set_position(f, destpos);
1041 mp4ff_set_metadata_name(parent_atom_type, &name);
1043 mp4ff_tag_add_field(&(f->tags), name, data, len);
1052 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1057 if (f->total_tracks == 0)
1060 version = mp4ff_read_int32(f);
1062 mp4ff_read_int64(f); //creation-time
1063 mp4ff_read_int64(f); //modification-time
1064 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1065 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1066 } else //version == 0
1070 mp4ff_read_int32(f); //creation-time
1071 mp4ff_read_int32(f); //modification-time
1072 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1073 temp = mp4ff_read_int32(f);
1074 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1076 mp4ff_read_int16(f);
1077 mp4ff_read_int16(f);
1081 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1083 uint64_t subsize, sumsize = 0;
1085 uint8_t header_size = 0;
1087 while (sumsize < size) {
1088 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1091 mp4ff_parse_tag(f, atom_type,
1092 (uint32_t) (subsize - header_size));
1099 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1101 uint64_t subsize, sumsize = 0;
1103 uint8_t header_size = 0;
1105 mp4ff_read_char(f); /* version */
1106 mp4ff_read_int24(f); /* flags */
1108 while (sumsize < (size - (header_size + 4))) {
1109 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1110 if (subsize <= header_size + 4)
1112 if (atom_type == ATOM_ILST) {
1113 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1115 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1123 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1124 const uint8_t atom_type)
1126 uint64_t dest_position = mp4ff_position(f) + size - 8;
1127 if (atom_type == ATOM_STSZ) {
1128 /* sample size box */
1130 } else if (atom_type == ATOM_STTS) {
1131 /* time to sample box */
1133 } else if (atom_type == ATOM_CTTS) {
1134 /* composition offset box */
1136 } else if (atom_type == ATOM_STSC) {
1137 /* sample to chunk box */
1139 } else if (atom_type == ATOM_STCO) {
1140 /* chunk offset box */
1142 } else if (atom_type == ATOM_STSD) {
1143 /* sample description box */
1145 } else if (atom_type == ATOM_MVHD) {
1146 /* movie header box */
1148 } else if (atom_type == ATOM_MDHD) {
1151 } else if (atom_type == ATOM_META) {
1152 /* iTunes Metadata box */
1153 mp4ff_read_meta(f, size);
1156 mp4ff_set_position(f, dest_position);
1160 /* parse atoms that are sub atoms of other atoms */
1161 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1164 uint8_t atom_type = 0;
1165 uint64_t counted_size = 0;
1166 uint8_t header_size = 0;
1168 while (counted_size < total_size) {
1169 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1170 counted_size += size;
1172 /* check for end of file */
1176 /* we're starting to read a new track, update index,
1177 * so that all data and tables get written in the right place
1179 if (atom_type == ATOM_TRAK) {
1183 /* parse subatoms */
1184 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1185 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1186 } else if (atom_type < SUBATOMIC) {
1187 parse_sub_atoms(f, size - header_size, meta_only);
1189 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1196 /* parse root atoms */
1197 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1200 uint8_t atom_type = 0;
1201 uint8_t header_size = 0;
1204 f->stream->read_error = 0;
1207 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1208 f->file_size += size;
1209 f->last_atom = atom_type;
1211 if (atom_type == ATOM_MOOV && size > header_size) {
1212 f->moov_offset = mp4ff_position(f) - header_size;
1213 f->moov_size = size;
1216 /* parse subatoms */
1217 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1218 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1219 } else if (atom_type < SUBATOMIC) {
1220 parse_sub_atoms(f, size - header_size, meta_only);
1222 /* skip this atom */
1223 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1230 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1231 unsigned char **ppBuf, unsigned int *pBufSize)
1233 if (track >= f->total_tracks) {
1239 if (f->track[track]->decoderConfig == NULL
1240 || f->track[track]->decoderConfigLen == 0) {
1244 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1245 memcpy(*ppBuf, f->track[track]->decoderConfig,
1246 f->track[track]->decoderConfigLen);
1247 *pBufSize = f->track[track]->decoderConfigLen;
1251 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1253 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1267 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1271 for (i = 0; i < tags->count; i++) {
1272 free(tags->tags[i].item);
1273 free(tags->tags[i].value);
1282 void mp4ff_close(mp4ff_t * ff)
1286 for (i = 0; i < ff->total_tracks; i++) {
1288 free(ff->track[i]->stsz_table);
1289 free(ff->track[i]->stts_sample_count);
1290 free(ff->track[i]->stts_sample_delta);
1291 free(ff->track[i]->stsc_first_chunk);
1292 free(ff->track[i]->stsc_samples_per_chunk);
1293 free(ff->track[i]->stsc_sample_desc_index);
1294 free(ff->track[i]->stco_chunk_offset);
1295 free(ff->track[i]->decoderConfig);
1296 free(ff->track[i]->ctts_sample_count);
1297 free(ff->track[i]->ctts_sample_offset);
1302 mp4ff_tag_delete(&(ff->tags));
1306 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1307 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1309 int32_t total_entries = 0;
1310 int32_t chunk2entry;
1311 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1315 if (f->track[track] == NULL) {
1319 total_entries = f->track[track]->stsc_entry_count;
1326 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1327 *chunk = chunk2 - chunk1;
1328 range_samples = *chunk * chunk1samples;
1330 if (sample < total + range_samples)
1333 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1336 if (chunk2entry < total_entries) {
1338 total += range_samples;
1340 } while (chunk2entry < total_entries);
1343 *chunk = (sample - total) / chunk1samples + chunk1;
1347 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1352 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1353 const int32_t chunk)
1355 const mp4ff_track_t *p_track = f->track[track];
1357 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1358 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1360 } else if (p_track->stco_entry_count) {
1361 return p_track->stco_chunk_offset[chunk - 1];
1369 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1370 const int32_t chunk_sample, const int32_t sample)
1373 const mp4ff_track_t *p_track = f->track[track];
1375 if (p_track->stsz_sample_size) {
1376 return (sample - chunk_sample) * p_track->stsz_sample_size;
1378 if (sample >= p_track->stsz_sample_count)
1381 for (i = chunk_sample, total = 0; i < sample; i++) {
1382 total += p_track->stsz_table[i];
1388 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1389 const int32_t sample)
1391 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1393 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1395 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1396 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1397 track, chunk_sample, sample);
1398 return chunk_offset2;
1401 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1402 const int32_t sample)
1404 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1405 mp4ff_set_position(f, offset);
1408 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1410 const mp4ff_track_t *t = f->track[track];
1412 if (t->stsz_sample_size != 0)
1413 return t->stsz_sample_size;
1414 return t->stsz_table[sample];
1417 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1419 return f->track[track]->sampleRate;
1422 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1424 return f->track[track]->channelCount;
1427 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1432 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1433 total += f->track[track]->stts_sample_count[i];
1438 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1440 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1454 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1456 return f->tags.count;
1459 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1460 char **item, char **value)
1462 if (index >= f->tags.count) {
1467 *item = para_strdup(f->tags.tags[index].item);
1468 *value = para_strdup(f->tags.tags[index].value);
1473 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1476 uint32_t remaining = size;
1477 uint64_t atom_offset = base;
1482 mp4ff_set_position(f, atom_offset);
1486 atom_size = mp4ff_read_int32(f);
1487 if (atom_size > remaining || atom_size < 8)
1489 mp4ff_read_data(f, atom_name, 4);
1491 if (!memcmp(atom_name, name, 4)) {
1492 mp4ff_set_position(f, atom_offset);
1496 remaining -= atom_size;
1497 atom_offset += atom_size;
1501 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1502 const char *name, uint32_t extraheaders, const char *name_inside)
1504 uint64_t first_base = (uint64_t) (-1);
1505 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1507 uint64_t mybase = mp4ff_position(f);
1508 uint32_t mysize = mp4ff_read_int32(f);
1510 if (first_base == (uint64_t) (-1))
1511 first_base = mybase;
1513 if (mysize < 8 + extraheaders)
1516 if (find_atom (f, mybase + (8 + extraheaders),
1517 mysize - (8 + extraheaders), name_inside)) {
1518 mp4ff_set_position(f, mybase);
1522 if (size <= mysize) {
1529 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1531 mp4ff_set_position(f, first_base);
1544 #define stricmp strcasecmp
1546 static membuffer *membuffer_create(void)
1548 const unsigned initial_size = 256;
1550 membuffer *buf = para_malloc(sizeof (membuffer));
1551 buf->data = para_malloc(initial_size);
1553 buf->allocated = initial_size;
1554 buf->error = buf->data == 0 ? 1 : 0;
1559 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1561 unsigned dest_size = buf->written + bytes;
1565 if (dest_size > buf->allocated) {
1567 buf->allocated <<= 1;
1568 } while (dest_size > buf->allocated);
1571 void *newptr = realloc(buf->data, buf->allocated);
1583 memcpy((char *) buf->data + buf->written, ptr, bytes);
1584 buf->written += bytes;
1588 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1590 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1593 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1595 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1596 return membuffer_write(buf, temp, 2);
1599 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1601 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1602 (uint8_t) (data >> 8), (uint8_t) data };
1603 return membuffer_write(buf, temp, 4);
1606 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1607 uint32_t index, uint32_t total)
1609 membuffer_write_int32(buf,
1610 8 /*atom header */ + 8 /*data atom header */ +
1611 8 /*flags + reserved */ + 8 /*actual data */ );
1612 membuffer_write_atom_name(buf, name);
1613 membuffer_write_int32(buf,
1614 8 /*data atom header */ +
1615 8 /*flags + reserved */ + 8 /*actual data */ );
1616 membuffer_write_atom_name(buf, "data");
1617 membuffer_write_int32(buf, 0); //flags
1618 membuffer_write_int32(buf, 0); //reserved
1619 membuffer_write_int16(buf, 0);
1620 membuffer_write_int16(buf, (uint16_t) index); //track number
1621 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1622 membuffer_write_int16(buf, 0);
1625 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1628 membuffer_write_int32(buf,
1629 8 /*atom header */ + 8 /*data atom header */ +
1630 8 /*flags + reserved */ + 2 /*actual data */ );
1631 membuffer_write_atom_name(buf, name);
1632 membuffer_write_int32(buf,
1633 8 /*data atom header */ +
1634 8 /*flags + reserved */ + 2 /*actual data */ );
1635 membuffer_write_atom_name(buf, "data");
1636 membuffer_write_int32(buf, 0); //flags
1637 membuffer_write_int32(buf, 0); //reserved
1638 membuffer_write_int16(buf, value); //value
1641 static uint32_t myatoi(const char *param)
1643 return param ? atoi(param) : 0;
1646 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1649 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1650 if (!stricmp(genrestr, ID3v1GenreList[n]))
1661 static stdmeta_entry stdmetas[] = {
1662 {"\xA9" "nam", "title"},
1663 {"\xA9" "ART", "artist"},
1664 {"\xA9" "wrt", "writer"},
1665 {"\xA9" "alb", "album"},
1666 {"\xA9" "day", "date"},
1667 {"\xA9" "too", "tool"},
1668 {"\xA9" "cmt", "comment"},
1669 {"cpil", "compilation"},
1671 {"aART", "album_artist"},
1674 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1677 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1678 if (!stricmp(name, stdmetas[n].name))
1679 return stdmetas[n].atom;
1684 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1689 /* special check for compilation flag */
1690 if (strcmp(name, "cpil") == 0) {
1694 membuffer_write_int32(buf,
1695 8 /*atom header */ + 8 /*data atom header */ +
1696 8 /*flags + reserved */ + strlen(value));
1697 membuffer_write_atom_name(buf, name);
1698 membuffer_write_int32(buf,
1699 8 /*data atom header */ +
1700 8 /*flags + reserved */ + strlen(value));
1701 membuffer_write_atom_name(buf, "data");
1702 membuffer_write_int32(buf, flags); //flags
1703 membuffer_write_int32(buf, 0); //reserved
1704 membuffer_write(buf, value, strlen(value));
1707 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1710 membuffer_write_int32(buf,
1711 8 /*atom header */ +
1712 0x1C /*weirdo itunes atom */ +
1713 12 /*name atom header */ + strlen(name) +
1714 16 /*data atom header + flags */ + strlen(value));
1715 membuffer_write_atom_name(buf, "----");
1716 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1717 membuffer_write_atom_name(buf, "mean");
1718 membuffer_write_int32(buf, 0);
1719 membuffer_write(buf, "com.apple.iTunes", 16);
1720 membuffer_write_int32(buf, 12 + strlen(name));
1721 membuffer_write_atom_name(buf, "name");
1722 membuffer_write_int32(buf, 0);
1723 membuffer_write(buf, name, strlen(name));
1724 membuffer_write_int32(buf,
1725 8 /*data atom header */ +
1726 8 /*flags + reserved */ + strlen(value));
1727 membuffer_write_atom_name(buf, "data");
1728 membuffer_write_int32(buf, 1); //flags
1729 membuffer_write_int32(buf, 0); //reserved
1730 membuffer_write(buf, value, strlen(value));
1733 static unsigned membuffer_error(const membuffer * buf)
1738 static void membuffer_free(membuffer * buf)
1744 static unsigned membuffer_get_size(const membuffer * buf)
1746 return buf->written;
1749 static void *membuffer_detach(membuffer * buf)
1756 ret = realloc(buf->data, buf->written);
1767 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1768 uint32_t * out_size)
1770 membuffer *buf = membuffer_create();
1772 char *mask = para_calloc(data->count);
1774 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1775 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1776 const char *genre_ptr = 0, *tempo_ptr = 0;
1777 for (metaptr = 0; metaptr < data->count; metaptr++) {
1778 mp4ff_tag_t *tag = &data->tags[metaptr];
1779 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1780 if (tracknumber_ptr == 0)
1781 tracknumber_ptr = tag->value;
1783 } else if (!stricmp(tag->item, "totaltracks")) {
1784 if (totaltracks_ptr == 0)
1785 totaltracks_ptr = tag->value;
1787 } else if (!stricmp(tag->item, "discnumber")
1788 || !stricmp(tag->item, "disc")) {
1789 if (discnumber_ptr == 0)
1790 discnumber_ptr = tag->value;
1792 } else if (!stricmp(tag->item, "totaldiscs")) {
1793 if (totaldiscs_ptr == 0)
1794 totaldiscs_ptr = tag->value;
1796 } else if (!stricmp(tag->item, "genre")) {
1798 genre_ptr = tag->value;
1800 } else if (!stricmp(tag->item, "tempo")) {
1802 tempo_ptr = tag->value;
1808 if (tracknumber_ptr)
1809 membuffer_write_track_tag(buf, "trkn",
1810 myatoi(tracknumber_ptr),
1811 myatoi(totaltracks_ptr));
1813 membuffer_write_track_tag(buf, "disk",
1814 myatoi(discnumber_ptr),
1815 myatoi(totaldiscs_ptr));
1817 membuffer_write_int16_tag(buf, "tmpo",
1818 (uint16_t) myatoi(tempo_ptr));
1821 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1823 membuffer_write_std_tag(buf, "©gen",
1826 membuffer_write_int16_tag(buf, "gnre",
1831 for (metaptr = 0; metaptr < data->count; metaptr++) {
1832 if (!mask[metaptr]) {
1833 mp4ff_tag_t *tag = &data->tags[metaptr];
1834 const char *std_meta_atom = find_standard_meta(tag->item);
1835 if (std_meta_atom) {
1836 membuffer_write_std_tag(buf, std_meta_atom,
1839 membuffer_write_custom_tag(buf, tag->item,
1847 if (membuffer_error(buf)) {
1848 membuffer_free(buf);
1852 *out_size = membuffer_get_size(buf);
1853 *out_buffer = membuffer_detach(buf);
1854 membuffer_free(buf);
1859 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1862 membuffer_write_int32(buf, size + 8);
1863 membuffer_write_atom_name(buf, name);
1864 membuffer_write(buf, data, size);
1867 static void *membuffer_get_ptr(const membuffer * buf)
1872 static void membuffer_set_error(membuffer * buf)
1877 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1883 oldsize = membuffer_get_size(buf);
1884 if (membuffer_write(buf, 0, bytes) != bytes)
1887 bufptr = membuffer_get_ptr(buf);
1891 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1893 membuffer_set_error(buf);
1900 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1901 uint32_t * out_size)
1907 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1910 buf = membuffer_create();
1912 membuffer_write_int32(buf, 0);
1913 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1916 *out_size = membuffer_get_size(buf);
1917 *out_buffer = membuffer_detach(buf);
1918 membuffer_free(buf);
1922 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1923 uint32_t * out_size)
1929 if (!create_meta(data, &meta_buffer, &meta_size))
1932 buf = membuffer_create();
1934 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1938 *out_size = membuffer_get_size(buf);
1939 *out_buffer = membuffer_detach(buf);
1940 membuffer_free(buf);
1944 static uint32_t fix_byte_order_32(uint32_t src)
1947 uint32_t a, b, c, d;
1950 memcpy(data, &src, sizeof (src));
1951 a = (uint8_t) data[0];
1952 b = (uint8_t) data[1];
1953 c = (uint8_t) data[2];
1954 d = (uint8_t) data[3];
1956 result = (a << 24) | (b << 16) | (c << 8) | d;
1957 return (uint32_t) result;
1960 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1961 void **out_buffer, uint32_t * out_size)
1963 uint64_t total_base = f->moov_offset + 8;
1964 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1966 uint64_t udta_offset, meta_offset, ilst_offset;
1967 uint32_t udta_size, meta_size, ilst_size;
1969 uint32_t new_ilst_size;
1970 void *new_ilst_buffer;
1975 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1977 void *new_udta_buffer;
1978 uint32_t new_udta_size;
1979 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1982 buf = membuffer_create();
1983 mp4ff_set_position(f, total_base);
1984 membuffer_transfer_from_file(buf, f, total_size);
1986 membuffer_write_atom(buf, "udta", new_udta_size,
1989 free(new_udta_buffer);
1991 *out_size = membuffer_get_size(buf);
1992 *out_buffer = membuffer_detach(buf);
1993 membuffer_free(buf);
1996 udta_offset = mp4ff_position(f);
1997 udta_size = mp4ff_read_int32(f);
1998 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2000 void *new_meta_buffer;
2001 uint32_t new_meta_size;
2002 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2005 buf = membuffer_create();
2006 mp4ff_set_position(f, total_base);
2007 membuffer_transfer_from_file(buf, f,
2008 (uint32_t)(udta_offset - total_base));
2010 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2011 membuffer_write_atom_name(buf, "udta");
2012 membuffer_transfer_from_file(buf, f, udta_size);
2014 membuffer_write_atom(buf, "meta", new_meta_size,
2016 free(new_meta_buffer);
2018 *out_size = membuffer_get_size(buf);
2019 *out_buffer = membuffer_detach(buf);
2020 membuffer_free(buf);
2023 meta_offset = mp4ff_position(f);
2024 meta_size = mp4ff_read_int32(f);
2025 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2026 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2027 ilst_offset = mp4ff_position(f);
2028 ilst_size = mp4ff_read_int32(f);
2030 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2033 size_delta = new_ilst_size - (ilst_size - 8);
2035 *out_size = total_size + size_delta;
2036 *out_buffer = para_malloc(*out_size);
2037 p_out = (uint8_t *) * out_buffer;
2039 mp4ff_set_position(f, total_base);
2040 mp4ff_read_data(f, p_out,
2041 (uint32_t) (udta_offset - total_base));
2042 p_out += (uint32_t) (udta_offset - total_base);
2043 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2045 mp4ff_read_data(f, p_out, 4);
2047 mp4ff_read_data(f, p_out,
2048 (uint32_t) (meta_offset - udta_offset - 8));
2049 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2050 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2052 mp4ff_read_data(f, p_out, 4);
2054 mp4ff_read_data(f, p_out,
2055 (uint32_t) (ilst_offset - meta_offset - 8));
2056 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2057 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2059 mp4ff_read_data(f, p_out, 4);
2062 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2063 p_out += new_ilst_size;
2065 mp4ff_set_position(f, ilst_offset + ilst_size);
2066 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2067 - (ilst_offset - total_base) - ilst_size));
2069 free(new_ilst_buffer);
2074 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2078 result = f->stream->write(f->stream->user_data, data, size);
2080 f->current_position += size;
2085 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2088 uint32_t a, b, c, d;
2091 *(uint32_t *) temp = data;
2092 a = (uint8_t) temp[0];
2093 b = (uint8_t) temp[1];
2094 c = (uint8_t) temp[2];
2095 d = (uint8_t) temp[3];
2097 result = (a << 24) | (b << 16) | (c << 8) | d;
2099 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2102 static int32_t mp4ff_truncate(mp4ff_t * f)
2104 return f->stream->truncate(f->stream->user_data);
2107 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2109 void *new_moov_data;
2110 uint32_t new_moov_size;
2112 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2114 mp4ff_set_position(ff, 0);
2118 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2123 /* copy moov atom to end of the file */
2124 if (ff->last_atom != ATOM_MOOV) {
2125 char *free_data = "free";
2127 /* rename old moov to free */
2128 mp4ff_set_position(ff, ff->moov_offset + 4);
2129 mp4ff_write_data(ff, free_data, 4);
2131 mp4ff_set_position(ff, ff->file_size);
2132 mp4ff_write_int32(ff, new_moov_size + 8);
2133 mp4ff_write_data(ff, "moov", 4);
2134 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2136 mp4ff_set_position(ff, ff->moov_offset);
2137 mp4ff_write_int32(ff, new_moov_size + 8);
2138 mp4ff_write_data(ff, "moov", 4);
2139 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2148 /* find a metadata item by name */
2149 /* returns 0 if item found, 1 if no such item */
2150 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2155 for (i = 0; i < f->tags.count; i++) {
2156 if (!stricmp(f->tags.tags[i].item, item)) {
2157 *value = para_strdup(f->tags.tags[i].value);
2168 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2170 return mp4ff_meta_find_by_name(f, "artist", value);
2173 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2175 return mp4ff_meta_find_by_name(f, "title", value);
2178 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2180 return mp4ff_meta_find_by_name(f, "date", value);
2183 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2185 return mp4ff_meta_find_by_name(f, "album", value);
2188 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2190 return mp4ff_meta_find_by_name(f, "comment", value);