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 = 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 = strdup(value);
786 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
787 free(tags->tags[tags->count].item);
788 free(tags->tags[tags->count].value);
789 tags->tags[tags->count].item = NULL;
790 tags->tags[tags->count].value = NULL;
791 tags->tags[tags->count].len = 0;
800 static const char *ID3v1GenreList[] = {
801 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
802 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
803 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
804 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
805 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
806 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
807 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
808 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
809 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
810 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
811 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
812 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
813 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
814 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
815 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
816 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
817 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
818 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
819 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
820 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
821 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
822 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
823 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
824 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
825 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
826 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
827 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
828 "Anime", "JPop", "SynthPop",
831 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
833 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
834 return ID3v1GenreList[idx - 1];
840 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
842 char *str = para_malloc(length + 1);
843 if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
851 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
853 static char *tag_names[] = {
854 "unknown", "title", "artist", "writer", "album",
855 "date", "tool", "comment", "genre", "track",
856 "disc", "compilation", "genre", "tempo", "cover",
857 "album_artist", "contentgroup", "lyrics", "description",
858 "network", "show", "episodename",
859 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
860 "sortwriter", "sortshow",
861 "season", "episode", "podcast"
896 case ATOM_COMPILATION:
908 case ATOM_ALBUM_ARTIST:
911 case ATOM_CONTENTGROUP:
917 case ATOM_DESCRIPTION:
926 case ATOM_EPISODENAME:
935 case ATOM_SORTARTIST:
938 case ATOM_SORTALBUMARTIST:
941 case ATOM_SORTWRITER:
961 *name = strdup(tag_names[tag_idx]);
966 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
970 uint8_t header_size = 0;
971 uint64_t subsize, sumsize = 0;
977 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
979 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
980 destpos = mp4ff_position(f) + subsize - header_size;
983 if (atom_type == ATOM_DATA) {
984 mp4ff_read_char(f); /* version */
985 mp4ff_read_int24(f); /* flags */
986 mp4ff_read_int32(f); /* reserved */
988 /* some need special attention */
989 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
990 if (subsize - header_size >= 8 + 2) {
991 uint16_t val = mp4ff_read_int16(f);
993 if (parent_atom_type == ATOM_TEMPO) {
998 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1000 const char *temp = mp4ff_meta_index_to_genre(val);
1002 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1007 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1008 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1009 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1010 +sizeof (uint16_t) /* track / disc */
1011 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1012 uint16_t index, total;
1014 mp4ff_read_int16(f);
1015 index = mp4ff_read_int16(f);
1016 total = mp4ff_read_int16(f);
1017 if (parent_atom_type == ATOM_TRACK)
1018 mp4ff_read_int16(f);
1020 sprintf(temp, "%d", index);
1021 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1022 "track" : "disc", temp, -1);
1026 mp4ff_tag_add_field(& (f-> tags),
1027 parent_atom_type == ATOM_TRACK?
1028 "totaltracks" : "totaldiscs", temp, -1);
1034 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1035 len = (uint32_t) (subsize - (header_size + 8));
1037 } else if (atom_type == ATOM_NAME) {
1039 mp4ff_read_char(f); /* version */
1040 mp4ff_read_int24(f); /* flags */
1042 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1045 mp4ff_set_position(f, destpos);
1052 mp4ff_set_metadata_name(parent_atom_type, &name);
1054 mp4ff_tag_add_field(&(f->tags), name, data, len);
1063 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1068 if (f->total_tracks == 0)
1071 version = mp4ff_read_int32(f);
1073 mp4ff_read_int64(f); //creation-time
1074 mp4ff_read_int64(f); //modification-time
1075 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1076 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1077 } else //version == 0
1081 mp4ff_read_int32(f); //creation-time
1082 mp4ff_read_int32(f); //modification-time
1083 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1084 temp = mp4ff_read_int32(f);
1085 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1087 mp4ff_read_int16(f);
1088 mp4ff_read_int16(f);
1092 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1094 uint64_t subsize, sumsize = 0;
1096 uint8_t header_size = 0;
1098 while (sumsize < size) {
1099 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1102 mp4ff_parse_tag(f, atom_type,
1103 (uint32_t) (subsize - header_size));
1110 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1112 uint64_t subsize, sumsize = 0;
1114 uint8_t header_size = 0;
1116 mp4ff_read_char(f); /* version */
1117 mp4ff_read_int24(f); /* flags */
1119 while (sumsize < (size - (header_size + 4))) {
1120 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1121 if (subsize <= header_size + 4)
1123 if (atom_type == ATOM_ILST) {
1124 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1126 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1134 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1135 const uint8_t atom_type)
1137 uint64_t dest_position = mp4ff_position(f) + size - 8;
1138 if (atom_type == ATOM_STSZ) {
1139 /* sample size box */
1141 } else if (atom_type == ATOM_STTS) {
1142 /* time to sample box */
1144 } else if (atom_type == ATOM_CTTS) {
1145 /* composition offset box */
1147 } else if (atom_type == ATOM_STSC) {
1148 /* sample to chunk box */
1150 } else if (atom_type == ATOM_STCO) {
1151 /* chunk offset box */
1153 } else if (atom_type == ATOM_STSD) {
1154 /* sample description box */
1156 } else if (atom_type == ATOM_MVHD) {
1157 /* movie header box */
1159 } else if (atom_type == ATOM_MDHD) {
1162 } else if (atom_type == ATOM_META) {
1163 /* iTunes Metadata box */
1164 mp4ff_read_meta(f, size);
1167 mp4ff_set_position(f, dest_position);
1171 /* parse atoms that are sub atoms of other atoms */
1172 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1175 uint8_t atom_type = 0;
1176 uint64_t counted_size = 0;
1177 uint8_t header_size = 0;
1179 while (counted_size < total_size) {
1180 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1181 counted_size += size;
1183 /* check for end of file */
1187 /* we're starting to read a new track, update index,
1188 * so that all data and tables get written in the right place
1190 if (atom_type == ATOM_TRAK) {
1194 /* parse subatoms */
1195 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1196 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1197 } else if (atom_type < SUBATOMIC) {
1198 parse_sub_atoms(f, size - header_size, meta_only);
1200 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1207 /* parse root atoms */
1208 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1211 uint8_t atom_type = 0;
1212 uint8_t header_size = 0;
1215 f->stream->read_error = 0;
1218 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1219 f->file_size += size;
1220 f->last_atom = atom_type;
1222 if (atom_type == ATOM_MOOV && size > header_size) {
1223 f->moov_offset = mp4ff_position(f) - header_size;
1224 f->moov_size = size;
1227 /* parse subatoms */
1228 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1229 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1230 } else if (atom_type < SUBATOMIC) {
1231 parse_sub_atoms(f, size - header_size, meta_only);
1233 /* skip this atom */
1234 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1241 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1242 unsigned char **ppBuf, unsigned int *pBufSize)
1244 if (track >= f->total_tracks) {
1250 if (f->track[track]->decoderConfig == NULL
1251 || f->track[track]->decoderConfigLen == 0) {
1255 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1256 memcpy(*ppBuf, f->track[track]->decoderConfig,
1257 f->track[track]->decoderConfigLen);
1258 *pBufSize = f->track[track]->decoderConfigLen;
1262 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1264 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1278 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1282 for (i = 0; i < tags->count; i++) {
1283 free(tags->tags[i].item);
1284 free(tags->tags[i].value);
1293 void mp4ff_close(mp4ff_t * ff)
1297 for (i = 0; i < ff->total_tracks; i++) {
1299 free(ff->track[i]->stsz_table);
1300 free(ff->track[i]->stts_sample_count);
1301 free(ff->track[i]->stts_sample_delta);
1302 free(ff->track[i]->stsc_first_chunk);
1303 free(ff->track[i]->stsc_samples_per_chunk);
1304 free(ff->track[i]->stsc_sample_desc_index);
1305 free(ff->track[i]->stco_chunk_offset);
1306 free(ff->track[i]->decoderConfig);
1307 free(ff->track[i]->ctts_sample_count);
1308 free(ff->track[i]->ctts_sample_offset);
1313 mp4ff_tag_delete(&(ff->tags));
1317 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1318 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1320 int32_t total_entries = 0;
1321 int32_t chunk2entry;
1322 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1326 if (f->track[track] == NULL) {
1330 total_entries = f->track[track]->stsc_entry_count;
1337 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1338 *chunk = chunk2 - chunk1;
1339 range_samples = *chunk * chunk1samples;
1341 if (sample < total + range_samples)
1344 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1347 if (chunk2entry < total_entries) {
1349 total += range_samples;
1351 } while (chunk2entry < total_entries);
1354 *chunk = (sample - total) / chunk1samples + chunk1;
1358 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1363 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1364 const int32_t chunk)
1366 const mp4ff_track_t *p_track = f->track[track];
1368 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1369 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1371 } else if (p_track->stco_entry_count) {
1372 return p_track->stco_chunk_offset[chunk - 1];
1380 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1381 const int32_t chunk_sample, const int32_t sample)
1384 const mp4ff_track_t *p_track = f->track[track];
1386 if (p_track->stsz_sample_size) {
1387 return (sample - chunk_sample) * p_track->stsz_sample_size;
1389 if (sample >= p_track->stsz_sample_count)
1392 for (i = chunk_sample, total = 0; i < sample; i++) {
1393 total += p_track->stsz_table[i];
1399 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1400 const int32_t sample)
1402 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1404 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1406 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1407 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1408 track, chunk_sample, sample);
1409 return chunk_offset2;
1412 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1413 const int32_t sample)
1415 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1416 mp4ff_set_position(f, offset);
1419 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1421 const mp4ff_track_t *t = f->track[track];
1423 if (t->stsz_sample_size != 0)
1424 return t->stsz_sample_size;
1425 return t->stsz_table[sample];
1428 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1430 return f->track[track]->sampleRate;
1433 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1435 return f->track[track]->channelCount;
1438 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1443 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1444 total += f->track[track]->stts_sample_count[i];
1449 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1451 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1465 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1467 return f->tags.count;
1470 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1471 char **item, char **value)
1473 if (index >= f->tags.count) {
1478 *item = strdup(f->tags.tags[index].item);
1479 *value = strdup(f->tags.tags[index].value);
1484 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1487 uint32_t remaining = size;
1488 uint64_t atom_offset = base;
1493 mp4ff_set_position(f, atom_offset);
1497 atom_size = mp4ff_read_int32(f);
1498 if (atom_size > remaining || atom_size < 8)
1500 mp4ff_read_data(f, atom_name, 4);
1502 if (!memcmp(atom_name, name, 4)) {
1503 mp4ff_set_position(f, atom_offset);
1507 remaining -= atom_size;
1508 atom_offset += atom_size;
1512 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1513 const char *name, uint32_t extraheaders, const char *name_inside)
1515 uint64_t first_base = (uint64_t) (-1);
1516 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1518 uint64_t mybase = mp4ff_position(f);
1519 uint32_t mysize = mp4ff_read_int32(f);
1521 if (first_base == (uint64_t) (-1))
1522 first_base = mybase;
1524 if (mysize < 8 + extraheaders)
1527 if (find_atom (f, mybase + (8 + extraheaders),
1528 mysize - (8 + extraheaders), name_inside)) {
1529 mp4ff_set_position(f, mybase);
1533 if (size <= mysize) {
1540 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1542 mp4ff_set_position(f, first_base);
1555 #define stricmp strcasecmp
1557 static membuffer *membuffer_create(void)
1559 const unsigned initial_size = 256;
1561 membuffer *buf = para_malloc(sizeof (membuffer));
1562 buf->data = para_malloc(initial_size);
1564 buf->allocated = initial_size;
1565 buf->error = buf->data == 0 ? 1 : 0;
1570 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1572 unsigned dest_size = buf->written + bytes;
1576 if (dest_size > buf->allocated) {
1578 buf->allocated <<= 1;
1579 } while (dest_size > buf->allocated);
1582 void *newptr = realloc(buf->data, buf->allocated);
1594 memcpy((char *) buf->data + buf->written, ptr, bytes);
1595 buf->written += bytes;
1599 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1601 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1604 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1606 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1607 return membuffer_write(buf, temp, 2);
1610 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1612 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1613 (uint8_t) (data >> 8), (uint8_t) data };
1614 return membuffer_write(buf, temp, 4);
1617 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1618 uint32_t index, uint32_t total)
1620 membuffer_write_int32(buf,
1621 8 /*atom header */ + 8 /*data atom header */ +
1622 8 /*flags + reserved */ + 8 /*actual data */ );
1623 membuffer_write_atom_name(buf, name);
1624 membuffer_write_int32(buf,
1625 8 /*data atom header */ +
1626 8 /*flags + reserved */ + 8 /*actual data */ );
1627 membuffer_write_atom_name(buf, "data");
1628 membuffer_write_int32(buf, 0); //flags
1629 membuffer_write_int32(buf, 0); //reserved
1630 membuffer_write_int16(buf, 0);
1631 membuffer_write_int16(buf, (uint16_t) index); //track number
1632 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1633 membuffer_write_int16(buf, 0);
1636 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1639 membuffer_write_int32(buf,
1640 8 /*atom header */ + 8 /*data atom header */ +
1641 8 /*flags + reserved */ + 2 /*actual data */ );
1642 membuffer_write_atom_name(buf, name);
1643 membuffer_write_int32(buf,
1644 8 /*data atom header */ +
1645 8 /*flags + reserved */ + 2 /*actual data */ );
1646 membuffer_write_atom_name(buf, "data");
1647 membuffer_write_int32(buf, 0); //flags
1648 membuffer_write_int32(buf, 0); //reserved
1649 membuffer_write_int16(buf, value); //value
1652 static uint32_t myatoi(const char *param)
1654 return param ? atoi(param) : 0;
1657 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1660 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1661 if (!stricmp(genrestr, ID3v1GenreList[n]))
1672 static stdmeta_entry stdmetas[] = {
1673 {"\xA9" "nam", "title"},
1674 {"\xA9" "ART", "artist"},
1675 {"\xA9" "wrt", "writer"},
1676 {"\xA9" "alb", "album"},
1677 {"\xA9" "day", "date"},
1678 {"\xA9" "too", "tool"},
1679 {"\xA9" "cmt", "comment"},
1680 {"cpil", "compilation"},
1682 {"aART", "album_artist"},
1685 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1688 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1689 if (!stricmp(name, stdmetas[n].name))
1690 return stdmetas[n].atom;
1695 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1700 /* special check for compilation flag */
1701 if (strcmp(name, "cpil") == 0) {
1705 membuffer_write_int32(buf,
1706 8 /*atom header */ + 8 /*data atom header */ +
1707 8 /*flags + reserved */ + strlen(value));
1708 membuffer_write_atom_name(buf, name);
1709 membuffer_write_int32(buf,
1710 8 /*data atom header */ +
1711 8 /*flags + reserved */ + strlen(value));
1712 membuffer_write_atom_name(buf, "data");
1713 membuffer_write_int32(buf, flags); //flags
1714 membuffer_write_int32(buf, 0); //reserved
1715 membuffer_write(buf, value, strlen(value));
1718 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1721 membuffer_write_int32(buf,
1722 8 /*atom header */ +
1723 0x1C /*weirdo itunes atom */ +
1724 12 /*name atom header */ + strlen(name) +
1725 16 /*data atom header + flags */ + strlen(value));
1726 membuffer_write_atom_name(buf, "----");
1727 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1728 membuffer_write_atom_name(buf, "mean");
1729 membuffer_write_int32(buf, 0);
1730 membuffer_write(buf, "com.apple.iTunes", 16);
1731 membuffer_write_int32(buf, 12 + strlen(name));
1732 membuffer_write_atom_name(buf, "name");
1733 membuffer_write_int32(buf, 0);
1734 membuffer_write(buf, name, strlen(name));
1735 membuffer_write_int32(buf,
1736 8 /*data atom header */ +
1737 8 /*flags + reserved */ + strlen(value));
1738 membuffer_write_atom_name(buf, "data");
1739 membuffer_write_int32(buf, 1); //flags
1740 membuffer_write_int32(buf, 0); //reserved
1741 membuffer_write(buf, value, strlen(value));
1744 static unsigned membuffer_error(const membuffer * buf)
1749 static void membuffer_free(membuffer * buf)
1755 static unsigned membuffer_get_size(const membuffer * buf)
1757 return buf->written;
1760 static void *membuffer_detach(membuffer * buf)
1767 ret = realloc(buf->data, buf->written);
1778 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1779 uint32_t * out_size)
1781 membuffer *buf = membuffer_create();
1783 char *mask = para_calloc(data->count);
1785 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1786 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1787 const char *genre_ptr = 0, *tempo_ptr = 0;
1788 for (metaptr = 0; metaptr < data->count; metaptr++) {
1789 mp4ff_tag_t *tag = &data->tags[metaptr];
1790 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1791 if (tracknumber_ptr == 0)
1792 tracknumber_ptr = tag->value;
1794 } else if (!stricmp(tag->item, "totaltracks")) {
1795 if (totaltracks_ptr == 0)
1796 totaltracks_ptr = tag->value;
1798 } else if (!stricmp(tag->item, "discnumber")
1799 || !stricmp(tag->item, "disc")) {
1800 if (discnumber_ptr == 0)
1801 discnumber_ptr = tag->value;
1803 } else if (!stricmp(tag->item, "totaldiscs")) {
1804 if (totaldiscs_ptr == 0)
1805 totaldiscs_ptr = tag->value;
1807 } else if (!stricmp(tag->item, "genre")) {
1809 genre_ptr = tag->value;
1811 } else if (!stricmp(tag->item, "tempo")) {
1813 tempo_ptr = tag->value;
1819 if (tracknumber_ptr)
1820 membuffer_write_track_tag(buf, "trkn",
1821 myatoi(tracknumber_ptr),
1822 myatoi(totaltracks_ptr));
1824 membuffer_write_track_tag(buf, "disk",
1825 myatoi(discnumber_ptr),
1826 myatoi(totaldiscs_ptr));
1828 membuffer_write_int16_tag(buf, "tmpo",
1829 (uint16_t) myatoi(tempo_ptr));
1832 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1834 membuffer_write_std_tag(buf, "©gen",
1837 membuffer_write_int16_tag(buf, "gnre",
1842 for (metaptr = 0; metaptr < data->count; metaptr++) {
1843 if (!mask[metaptr]) {
1844 mp4ff_tag_t *tag = &data->tags[metaptr];
1845 const char *std_meta_atom = find_standard_meta(tag->item);
1846 if (std_meta_atom) {
1847 membuffer_write_std_tag(buf, std_meta_atom,
1850 membuffer_write_custom_tag(buf, tag->item,
1858 if (membuffer_error(buf)) {
1859 membuffer_free(buf);
1863 *out_size = membuffer_get_size(buf);
1864 *out_buffer = membuffer_detach(buf);
1865 membuffer_free(buf);
1870 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1873 membuffer_write_int32(buf, size + 8);
1874 membuffer_write_atom_name(buf, name);
1875 membuffer_write(buf, data, size);
1878 static void *membuffer_get_ptr(const membuffer * buf)
1883 static void membuffer_set_error(membuffer * buf)
1888 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1894 oldsize = membuffer_get_size(buf);
1895 if (membuffer_write(buf, 0, bytes) != bytes)
1898 bufptr = membuffer_get_ptr(buf);
1902 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1904 membuffer_set_error(buf);
1911 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1912 uint32_t * out_size)
1918 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1921 buf = membuffer_create();
1923 membuffer_write_int32(buf, 0);
1924 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1927 *out_size = membuffer_get_size(buf);
1928 *out_buffer = membuffer_detach(buf);
1929 membuffer_free(buf);
1933 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1934 uint32_t * out_size)
1940 if (!create_meta(data, &meta_buffer, &meta_size))
1943 buf = membuffer_create();
1945 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1949 *out_size = membuffer_get_size(buf);
1950 *out_buffer = membuffer_detach(buf);
1951 membuffer_free(buf);
1955 static uint32_t fix_byte_order_32(uint32_t src)
1958 uint32_t a, b, c, d;
1961 memcpy(data, &src, sizeof (src));
1962 a = (uint8_t) data[0];
1963 b = (uint8_t) data[1];
1964 c = (uint8_t) data[2];
1965 d = (uint8_t) data[3];
1967 result = (a << 24) | (b << 16) | (c << 8) | d;
1968 return (uint32_t) result;
1971 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1972 void **out_buffer, uint32_t * out_size)
1974 uint64_t total_base = f->moov_offset + 8;
1975 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1977 uint64_t udta_offset, meta_offset, ilst_offset;
1978 uint32_t udta_size, meta_size, ilst_size;
1980 uint32_t new_ilst_size;
1981 void *new_ilst_buffer;
1986 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1988 void *new_udta_buffer;
1989 uint32_t new_udta_size;
1990 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1993 buf = membuffer_create();
1994 mp4ff_set_position(f, total_base);
1995 membuffer_transfer_from_file(buf, f, total_size);
1997 membuffer_write_atom(buf, "udta", new_udta_size,
2000 free(new_udta_buffer);
2002 *out_size = membuffer_get_size(buf);
2003 *out_buffer = membuffer_detach(buf);
2004 membuffer_free(buf);
2007 udta_offset = mp4ff_position(f);
2008 udta_size = mp4ff_read_int32(f);
2009 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2011 void *new_meta_buffer;
2012 uint32_t new_meta_size;
2013 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2016 buf = membuffer_create();
2017 mp4ff_set_position(f, total_base);
2018 membuffer_transfer_from_file(buf, f,
2019 (uint32_t)(udta_offset - total_base));
2021 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2022 membuffer_write_atom_name(buf, "udta");
2023 membuffer_transfer_from_file(buf, f, udta_size);
2025 membuffer_write_atom(buf, "meta", new_meta_size,
2027 free(new_meta_buffer);
2029 *out_size = membuffer_get_size(buf);
2030 *out_buffer = membuffer_detach(buf);
2031 membuffer_free(buf);
2034 meta_offset = mp4ff_position(f);
2035 meta_size = mp4ff_read_int32(f);
2036 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2037 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2038 ilst_offset = mp4ff_position(f);
2039 ilst_size = mp4ff_read_int32(f);
2041 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2044 size_delta = new_ilst_size - (ilst_size - 8);
2046 *out_size = total_size + size_delta;
2047 *out_buffer = para_malloc(*out_size);
2048 p_out = (uint8_t *) * out_buffer;
2050 mp4ff_set_position(f, total_base);
2051 mp4ff_read_data(f, p_out,
2052 (uint32_t) (udta_offset - total_base));
2053 p_out += (uint32_t) (udta_offset - total_base);
2054 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2056 mp4ff_read_data(f, p_out, 4);
2058 mp4ff_read_data(f, p_out,
2059 (uint32_t) (meta_offset - udta_offset - 8));
2060 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2061 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2063 mp4ff_read_data(f, p_out, 4);
2065 mp4ff_read_data(f, p_out,
2066 (uint32_t) (ilst_offset - meta_offset - 8));
2067 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2068 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2070 mp4ff_read_data(f, p_out, 4);
2073 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2074 p_out += new_ilst_size;
2076 mp4ff_set_position(f, ilst_offset + ilst_size);
2077 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2078 - (ilst_offset - total_base) - ilst_size));
2080 free(new_ilst_buffer);
2085 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2089 result = f->stream->write(f->stream->user_data, data, size);
2091 f->current_position += size;
2096 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2099 uint32_t a, b, c, d;
2102 *(uint32_t *) temp = data;
2103 a = (uint8_t) temp[0];
2104 b = (uint8_t) temp[1];
2105 c = (uint8_t) temp[2];
2106 d = (uint8_t) temp[3];
2108 result = (a << 24) | (b << 16) | (c << 8) | d;
2110 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2113 static int32_t mp4ff_truncate(mp4ff_t * f)
2115 return f->stream->truncate(f->stream->user_data);
2118 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2120 void *new_moov_data;
2121 uint32_t new_moov_size;
2123 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2125 mp4ff_set_position(ff, 0);
2129 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2134 /* copy moov atom to end of the file */
2135 if (ff->last_atom != ATOM_MOOV) {
2136 char *free_data = "free";
2138 /* rename old moov to free */
2139 mp4ff_set_position(ff, ff->moov_offset + 4);
2140 mp4ff_write_data(ff, free_data, 4);
2142 mp4ff_set_position(ff, ff->file_size);
2143 mp4ff_write_int32(ff, new_moov_size + 8);
2144 mp4ff_write_data(ff, "moov", 4);
2145 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2147 mp4ff_set_position(ff, ff->moov_offset);
2148 mp4ff_write_int32(ff, new_moov_size + 8);
2149 mp4ff_write_data(ff, "moov", 4);
2150 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2159 /* find a metadata item by name */
2160 /* returns 0 if item found, 1 if no such item */
2161 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2166 for (i = 0; i < f->tags.count; i++) {
2167 if (!stricmp(f->tags.tags[i].item, item)) {
2168 *value = strdup(f->tags.tags[i].value);
2179 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2181 return mp4ff_meta_find_by_name(f, "artist", value);
2184 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2186 return mp4ff_meta_find_by_name(f, "title", value);
2189 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2191 return mp4ff_meta_find_by_name(f, "date", value);
2194 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2196 return mp4ff_meta_find_by_name(f, "album", value);
2199 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2201 return mp4ff_meta_find_by_name(f, "comment", value);