2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
14 int32_t mp4ff_total_tracks(const mp4ff_t * f)
16 return f->total_tracks;
19 static int32_t mp4ff_read_data(mp4ff_t * f, void *data, uint32_t size)
23 result = f->stream->read(f->stream->user_data, data, size);
26 f->stream->read_error++;
28 f->current_position += size;
33 /* parse atom header size */
34 static int32_t mp4ff_atom_get_size(const int8_t * data)
39 a = (uint8_t) data[0];
40 b = (uint8_t) data[1];
41 c = (uint8_t) data[2];
42 d = (uint8_t) data[3];
44 result = (a << 24) | (b << 16) | (c << 8) | d;
45 return (int32_t) result;
48 static uint64_t mp4ff_read_int64(mp4ff_t * f)
54 mp4ff_read_data(f, data, 8);
56 for (i = 0; i < 8; i++) {
57 result |= ((uint64_t) data[i]) << ((7 - i) * 8);
63 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
64 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1,
65 const int8_t c1, const int8_t d1,
66 const int8_t a2, const int8_t b2,
67 const int8_t c2, const int8_t d2)
69 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
77 #define TRACK_SYSTEM 3
78 #define TRACK_UNKNOWN 0
80 /* atoms with subatoms */
88 #define ATOM_ILST 8 /* iTunes Metadata list */
90 #define ATOM_ARTIST 10
91 #define ATOM_WRITER 11
95 #define ATOM_COMMENT 15
96 #define ATOM_GENRE1 16
99 #define ATOM_COMPILATION 19
100 #define ATOM_GENRE2 20
101 #define ATOM_TEMPO 21
102 #define ATOM_COVER 22
107 #define SUBATOMIC 128
109 /* atoms without subatoms */
110 #define ATOM_FTYP 129
111 #define ATOM_MDAT 130
112 #define ATOM_MVHD 131
113 #define ATOM_TKHD 132
114 #define ATOM_TREF 133
115 #define ATOM_MDHD 134
116 #define ATOM_VMHD 135
117 #define ATOM_SMHD 136
118 #define ATOM_HMHD 137
119 #define ATOM_STSD 138
120 #define ATOM_STTS 139
121 #define ATOM_STSZ 140
122 #define ATOM_STZ2 141
123 #define ATOM_STCO 142
124 #define ATOM_STSC 143
125 #define ATOM_MP4A 144
126 #define ATOM_MP4V 145
127 #define ATOM_MP4S 146
128 #define ATOM_ESDS 147
129 #define ATOM_META 148 /* iTunes Metadata box */
130 #define ATOM_NAME 149 /* iTunes Metadata name box */
131 #define ATOM_DATA 150 /* iTunes Metadata data box */
132 #define ATOM_CTTS 151
133 #define ATOM_FRMA 152
134 #define ATOM_IVIV 153
135 #define ATOM_PRIV 154
136 #define ATOM_USER 155
138 #define ATOM_ALBUM_ARTIST 157
139 #define ATOM_CONTENTGROUP 158
140 #define ATOM_LYRICS 159
141 #define ATOM_DESCRIPTION 160
142 #define ATOM_NETWORK 161
143 #define ATOM_SHOW 162
144 #define ATOM_EPISODENAME 163
145 #define ATOM_SORTTITLE 164
146 #define ATOM_SORTALBUM 165
147 #define ATOM_SORTARTIST 166
148 #define ATOM_SORTALBUMARTIST 167
149 #define ATOM_SORTWRITER 168
150 #define ATOM_SORTSHOW 169
151 #define ATOM_SEASON 170
152 #define ATOM_EPISODE 171
153 #define ATOM_PODCAST 172
155 #define ATOM_UNKNOWN 255
156 #define ATOM_FREE ATOM_UNKNOWN
157 #define ATOM_SKIP ATOM_UNKNOWN
159 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
161 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
162 const int8_t c, const int8_t d)
165 if (mp4ff_atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
167 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
169 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
171 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
173 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
175 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
177 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
179 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
181 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
183 else if (mp4ff_atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
185 } else if (a == 't') {
186 if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
188 else if (mp4ff_atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
190 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
192 else if (mp4ff_atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
194 else if (mp4ff_atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
196 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
198 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
200 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
201 return ATOM_EPISODENAME;
202 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
204 else if (mp4ff_atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
206 } else if (a == 's') {
207 if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
209 else if (mp4ff_atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
211 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'd'))
213 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 't', 's'))
215 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
217 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'c'))
219 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 's', 'z'))
221 else if (mp4ff_atom_compare(a, b, c, d, 's', 't', 'z', '2'))
223 else if (mp4ff_atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
225 else if (mp4ff_atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
227 else if (mp4ff_atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
229 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
230 return ATOM_SORTTITLE;
231 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
232 return ATOM_SORTALBUM;
233 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
234 return ATOM_SORTARTIST;
235 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
236 return ATOM_SORTALBUMARTIST;
237 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
238 return ATOM_SORTWRITER;
239 else if (mp4ff_atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
240 return ATOM_SORTSHOW;
241 } else if (a == COPYRIGHT_SYMBOL) {
242 if (mp4ff_atom_compare
243 (a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
245 else if (mp4ff_atom_compare
246 (a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
248 else if (mp4ff_atom_compare
249 (a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
251 else if (mp4ff_atom_compare
252 (a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
254 else if (mp4ff_atom_compare
255 (a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
257 else if (mp4ff_atom_compare
258 (a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
260 else if (mp4ff_atom_compare
261 (a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
263 else if (mp4ff_atom_compare
264 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
266 else if (mp4ff_atom_compare
267 (a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
268 return ATOM_CONTENTGROUP;
269 else if (mp4ff_atom_compare
270 (a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
274 if (mp4ff_atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
276 else if (mp4ff_atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
278 else if (mp4ff_atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
280 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
282 else if (mp4ff_atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
284 else if (mp4ff_atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
286 else if (mp4ff_atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
288 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
290 else if (mp4ff_atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
292 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
294 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
296 else if (mp4ff_atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
298 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
300 else if (mp4ff_atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
301 return ATOM_COMPILATION;
302 else if (mp4ff_atom_compare(a, b, c, d, 'c', 't', 't', 's'))
304 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
306 else if (mp4ff_atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
308 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
310 else if (mp4ff_atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
312 else if (mp4ff_atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
314 else if (mp4ff_atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
316 else if (mp4ff_atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
317 return ATOM_ALBUM_ARTIST;
318 else if (mp4ff_atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
319 return ATOM_DESCRIPTION;
320 else if (mp4ff_atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
326 /* read atom header, return atom size, atom size is with header included */
327 static uint64_t mp4ff_atom_read_header(mp4ff_t * f, uint8_t * atom_type,
328 uint8_t * header_size)
332 int8_t atom_header[8];
334 ret = mp4ff_read_data(f, atom_header, 8);
338 size = mp4ff_atom_get_size(atom_header);
341 /* check for 64 bit atom size */
344 size = mp4ff_read_int64(f);
346 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5],
347 atom_header[6], atom_header[7]);
351 static int64_t mp4ff_position(const mp4ff_t * f)
353 return f->current_position;
356 static int need_parse_when_meta_only(uint8_t atom_type)
377 static int32_t mp4ff_set_position(mp4ff_t * f, const int64_t position)
379 f->stream->seek(f->stream->user_data, position);
380 f->current_position = position;
385 static void mp4ff_track_add(mp4ff_t * f)
389 if (f->total_tracks > MAX_TRACKS) {
394 f->track[f->total_tracks - 1] = para_calloc(sizeof (mp4ff_track_t));
397 static uint8_t mp4ff_read_char(mp4ff_t * f)
400 mp4ff_read_data(f, &output, 1);
404 static uint32_t mp4ff_read_int24(mp4ff_t * f)
410 mp4ff_read_data(f, data, 3);
411 a = (uint8_t) data[0];
412 b = (uint8_t) data[1];
413 c = (uint8_t) data[2];
415 result = (a << 16) | (b << 8) | c;
416 return (uint32_t) result;
419 static uint32_t mp4ff_read_int32(mp4ff_t * f)
425 mp4ff_read_data(f, data, 4);
426 a = (uint8_t) data[0];
427 b = (uint8_t) data[1];
428 c = (uint8_t) data[2];
429 d = (uint8_t) data[3];
431 result = (a << 24) | (b << 16) | (c << 8) | d;
432 return (uint32_t) result;
435 static int32_t mp4ff_read_stsz(mp4ff_t * f)
437 if (f->total_tracks == 0)
440 mp4ff_read_char(f); /* version */
441 mp4ff_read_int24(f); /* flags */
442 f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
443 f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
445 if (f->track[f->total_tracks - 1]->stsz_sample_size == 0) {
447 f->track[f->total_tracks - 1]->stsz_table =
448 para_malloc(f->track[f->total_tracks - 1]->stsz_sample_count
450 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count
451 && !f->stream->read_error; i++) {
452 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
458 static int32_t mp4ff_read_stts(mp4ff_t * f)
461 mp4ff_track_t *p_track;
464 if (f->total_tracks == 0)
467 p_track = f->track[f->total_tracks - 1];
469 if (p_track->stts_entry_count)
472 mp4ff_read_char(f); /* version */
473 mp4ff_read_int24(f); /* flags */
474 p_track->stts_entry_count = mp4ff_read_int32(f);
476 p_track->stts_sample_count = para_malloc(p_track->stts_entry_count
478 p_track->stts_sample_delta = para_malloc(p_track->stts_entry_count
480 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9254 */
481 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
482 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
487 static int32_t mp4ff_read_ctts(mp4ff_t * f)
490 mp4ff_track_t *p_track;
492 if (f->total_tracks == 0)
495 p_track = f->track[f->total_tracks - 1];
496 if (p_track->ctts_entry_count)
499 mp4ff_read_char(f); /* version */
500 mp4ff_read_int24(f); /* flags */
501 p_track->ctts_entry_count = mp4ff_read_int32(f);
503 p_track->ctts_sample_count = para_malloc(p_track->ctts_entry_count
505 p_track->ctts_sample_offset = para_malloc(p_track->ctts_entry_count
508 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9257 */
509 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
510 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
515 static int32_t mp4ff_read_stsc(mp4ff_t * f)
519 if (f->total_tracks == 0)
522 mp4ff_read_char(f); /* version */
523 mp4ff_read_int24(f); /* flags */
524 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
526 f->track[f->total_tracks - 1]->stsc_first_chunk =
527 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
529 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
530 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
532 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
533 para_malloc(f->track[f->total_tracks - 1]->stsc_entry_count *
536 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9255 */
537 f->track[f->total_tracks - 1]->stsc_first_chunk[i] =
539 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] =
541 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] =
548 static int32_t mp4ff_read_stco(mp4ff_t * f)
552 if (f->total_tracks == 0)
555 mp4ff_read_char(f); /* version */
556 mp4ff_read_int24(f); /* flags */
557 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
559 f->track[f->total_tracks - 1]->stco_chunk_offset =
560 para_malloc(f->track[f->total_tracks - 1]->stco_entry_count *
562 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9256 */
563 f->track[f->total_tracks - 1]->stco_chunk_offset[i] =
570 static uint16_t mp4ff_read_int16(mp4ff_t * f)
576 mp4ff_read_data(f, data, 2);
577 a = (uint8_t) data[0];
578 b = (uint8_t) data[1];
580 result = (a << 8) | b;
581 return (uint16_t) result;
584 static uint32_t mp4ff_read_mp4_descr_length(mp4ff_t * f)
587 uint8_t numBytes = 0;
591 b = mp4ff_read_char(f);
593 length = (length << 7) | (b & 0x7F);
594 } while ((b & 0x80) && numBytes < 4);
598 static int32_t mp4ff_read_esds(mp4ff_t * f)
603 if (f->total_tracks == 0)
606 mp4ff_read_char(f); /* version */
607 mp4ff_read_int24(f); /* flags */
609 /* get and verify ES_DescrTag */
610 tag = mp4ff_read_char(f);
613 if (mp4ff_read_mp4_descr_length(f) < 5 + 15) {
623 /* get and verify DecoderConfigDescrTab */
624 if (mp4ff_read_char(f) != 0x04) {
629 temp = mp4ff_read_mp4_descr_length(f);
633 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
634 mp4ff_read_int32(f); //0x15000414 ????
635 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
636 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
638 /* get and verify DecSpecificInfoTag */
639 if (mp4ff_read_char(f) != 0x05) {
644 f->track[f->total_tracks - 1]->decoderConfigLen =
645 mp4ff_read_mp4_descr_length(f);
647 free(f->track[f->total_tracks - 1]->decoderConfig);
648 f->track[f->total_tracks - 1]->decoderConfig =
649 para_malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
650 if (f->track[f->total_tracks - 1]->decoderConfig) {
651 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
652 f->track[f->total_tracks -
653 1]->decoderConfigLen);
655 /* will skip the remainder of the atom */
658 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
661 uint8_t atom_type = 0;
662 uint8_t header_size = 0;
664 if (f->total_tracks == 0)
667 for (i = 0; i < 6; i++) {
668 mp4ff_read_char(f); /* reserved */
670 /* data_reference_index */ mp4ff_read_int16(f);
672 mp4ff_read_int32(f); /* reserved */
673 mp4ff_read_int32(f); /* reserved */
675 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
676 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
681 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
685 mp4ff_atom_read_header(f, &atom_type, &header_size);
686 if (atom_type == ATOM_ESDS) {
693 static int32_t mp4ff_read_stsd(mp4ff_t * f)
696 uint8_t header_size = 0;
699 if (f->total_tracks == 0)
702 mp4ff_read_char(f); /* version */
703 mp4ff_read_int24(f); /* flags */
705 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
707 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
708 uint64_t skip = mp4ff_position(f);
710 uint8_t atom_type = 0;
711 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
714 if (atom_type == ATOM_MP4A) {
715 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
717 } else if (atom_type == ATOM_MP4V) {
718 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
719 } else if (atom_type == ATOM_MP4S) {
720 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
722 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
725 mp4ff_set_position(f, skip);
731 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
735 mp4ff_read_char(f); /* version */
736 mp4ff_read_int24(f); /* flags */
737 /* creation_time */ mp4ff_read_int32(f);
738 /* modification_time */ mp4ff_read_int32(f);
739 f->time_scale = mp4ff_read_int32(f);
740 f->duration = mp4ff_read_int32(f);
741 /* preferred_rate */ mp4ff_read_int32(f);
742 /*mp4ff_read_fixed32(f); */
743 /* preferred_volume */ mp4ff_read_int16(f);
744 /*mp4ff_read_fixed16(f); */
745 for (i = 0; i < 10; i++) {
746 /* reserved */ mp4ff_read_char(f);
748 for (i = 0; i < 9; i++) {
749 mp4ff_read_int32(f); /* matrix */
751 /* preview_time */ mp4ff_read_int32(f);
752 /* preview_duration */ mp4ff_read_int32(f);
753 /* poster_time */ mp4ff_read_int32(f);
754 /* selection_time */ mp4ff_read_int32(f);
755 /* selection_duration */ mp4ff_read_int32(f);
756 /* current_time */ mp4ff_read_int32(f);
757 /* next_track_id */ mp4ff_read_int32(f);
762 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
763 const char *value, int32_t len)
765 void *backup = (void *) tags->tags;
767 if (!item || (item && !*item) || !value)
770 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
771 (tags->count + 1) * sizeof (mp4ff_tag_t));
776 tags->tags[tags->count].item = para_strdup(item);
777 tags->tags[tags->count].len = len;
779 tags->tags[tags->count].value = para_malloc(len + 1);
780 memcpy(tags->tags[tags->count].value, value, len);
781 tags->tags[tags->count].value[len] = 0;
783 tags->tags[tags->count].value = para_strdup(value);
790 static const char *ID3v1GenreList[] = {
791 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
792 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
793 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
794 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
795 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
796 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
797 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
798 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
799 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
800 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
801 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
802 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
803 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
804 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
805 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
806 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
807 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
808 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
809 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
810 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
811 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
812 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
813 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
814 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
815 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
816 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
817 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
818 "Anime", "JPop", "SynthPop",
821 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
823 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
824 return ID3v1GenreList[idx - 1];
830 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
832 char *str = para_malloc(length + 1);
833 if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
841 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
843 static char *tag_names[] = {
844 "unknown", "title", "artist", "writer", "album",
845 "date", "tool", "comment", "genre", "track",
846 "disc", "compilation", "genre", "tempo", "cover",
847 "album_artist", "contentgroup", "lyrics", "description",
848 "network", "show", "episodename",
849 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
850 "sortwriter", "sortshow",
851 "season", "episode", "podcast"
886 case ATOM_COMPILATION:
898 case ATOM_ALBUM_ARTIST:
901 case ATOM_CONTENTGROUP:
907 case ATOM_DESCRIPTION:
916 case ATOM_EPISODENAME:
925 case ATOM_SORTARTIST:
928 case ATOM_SORTALBUMARTIST:
931 case ATOM_SORTWRITER:
951 *name = para_strdup(tag_names[tag_idx]);
955 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
959 uint8_t header_size = 0;
960 uint64_t subsize, sumsize;
969 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
970 mp4ff_set_position(f, destpos), sumsize += subsize
972 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
973 destpos = mp4ff_position(f) + subsize - header_size;
976 if (atom_type == ATOM_NAME) {
977 mp4ff_read_char(f); /* version */
978 mp4ff_read_int24(f); /* flags */
980 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
983 if (atom_type != ATOM_DATA)
985 mp4ff_read_char(f); /* version */
986 mp4ff_read_int24(f); /* flags */
987 mp4ff_read_int32(f); /* reserved */
989 /* some need special attention */
990 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
991 if (subsize - header_size >= 8 + 2) {
992 uint16_t val = mp4ff_read_int16(f);
994 if (parent_atom_type == ATOM_TEMPO) {
999 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1001 const char *temp = mp4ff_meta_index_to_genre(val);
1003 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1008 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1009 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1010 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1011 +sizeof (uint16_t) /* track / disc */
1012 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1013 uint16_t index, total;
1015 mp4ff_read_int16(f);
1016 index = mp4ff_read_int16(f);
1017 total = mp4ff_read_int16(f);
1018 if (parent_atom_type == ATOM_TRACK)
1019 mp4ff_read_int16(f);
1021 sprintf(temp, "%d", index);
1022 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1023 "track" : "disc", temp, -1);
1027 mp4ff_tag_add_field(& (f-> tags),
1028 parent_atom_type == ATOM_TRACK?
1029 "totaltracks" : "totaldiscs", temp, -1);
1035 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1036 len = (uint32_t) (subsize - (header_size + 8));
1042 mp4ff_set_metadata_name(parent_atom_type, &name);
1044 mp4ff_tag_add_field(&(f->tags), name, data, len);
1053 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1058 if (f->total_tracks == 0)
1061 version = mp4ff_read_int32(f);
1063 mp4ff_read_int64(f); //creation-time
1064 mp4ff_read_int64(f); //modification-time
1065 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1066 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1067 } else //version == 0
1071 mp4ff_read_int32(f); //creation-time
1072 mp4ff_read_int32(f); //modification-time
1073 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1074 temp = mp4ff_read_int32(f);
1075 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1077 mp4ff_read_int16(f);
1078 mp4ff_read_int16(f);
1082 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1084 uint64_t subsize, sumsize = 0;
1086 uint8_t header_size = 0;
1088 while (sumsize < size) {
1089 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1092 mp4ff_parse_tag(f, atom_type,
1093 (uint32_t) (subsize - header_size));
1100 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1102 uint64_t subsize, sumsize = 0;
1104 uint8_t header_size = 0;
1106 mp4ff_read_char(f); /* version */
1107 mp4ff_read_int24(f); /* flags */
1109 while (sumsize < (size - (header_size + 4))) {
1110 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1111 if (subsize <= header_size + 4)
1113 if (atom_type == ATOM_ILST) {
1114 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1116 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1124 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1125 const uint8_t atom_type)
1127 uint64_t dest_position = mp4ff_position(f) + size - 8;
1128 if (atom_type == ATOM_STSZ) {
1129 /* sample size box */
1131 } else if (atom_type == ATOM_STTS) {
1132 /* time to sample box */
1134 } else if (atom_type == ATOM_CTTS) {
1135 /* composition offset box */
1137 } else if (atom_type == ATOM_STSC) {
1138 /* sample to chunk box */
1140 } else if (atom_type == ATOM_STCO) {
1141 /* chunk offset box */
1143 } else if (atom_type == ATOM_STSD) {
1144 /* sample description box */
1146 } else if (atom_type == ATOM_MVHD) {
1147 /* movie header box */
1149 } else if (atom_type == ATOM_MDHD) {
1152 } else if (atom_type == ATOM_META) {
1153 /* iTunes Metadata box */
1154 mp4ff_read_meta(f, size);
1157 mp4ff_set_position(f, dest_position);
1161 /* parse atoms that are sub atoms of other atoms */
1162 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1165 uint8_t atom_type = 0;
1166 uint64_t counted_size = 0;
1167 uint8_t header_size = 0;
1169 while (counted_size < total_size) {
1170 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1171 counted_size += size;
1173 /* check for end of file */
1177 /* we're starting to read a new track, update index,
1178 * so that all data and tables get written in the right place
1180 if (atom_type == ATOM_TRAK) {
1184 /* parse subatoms */
1185 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1186 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1187 } else if (atom_type < SUBATOMIC) {
1188 parse_sub_atoms(f, size - header_size, meta_only);
1190 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1197 /* parse root atoms */
1198 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1201 uint8_t atom_type = 0;
1202 uint8_t header_size = 0;
1205 f->stream->read_error = 0;
1208 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1209 f->file_size += size;
1210 f->last_atom = atom_type;
1212 if (atom_type == ATOM_MOOV && size > header_size) {
1213 f->moov_offset = mp4ff_position(f) - header_size;
1214 f->moov_size = size;
1217 /* parse subatoms */
1218 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1219 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1220 } else if (atom_type < SUBATOMIC) {
1221 parse_sub_atoms(f, size - header_size, meta_only);
1223 /* skip this atom */
1224 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1231 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1232 unsigned char **ppBuf, unsigned int *pBufSize)
1234 if (track >= f->total_tracks) {
1240 if (f->track[track]->decoderConfig == NULL
1241 || f->track[track]->decoderConfigLen == 0) {
1245 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1246 memcpy(*ppBuf, f->track[track]->decoderConfig,
1247 f->track[track]->decoderConfigLen);
1248 *pBufSize = f->track[track]->decoderConfigLen;
1252 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1254 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1268 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1272 for (i = 0; i < tags->count; i++) {
1273 free(tags->tags[i].item);
1274 free(tags->tags[i].value);
1283 void mp4ff_close(mp4ff_t * ff)
1287 for (i = 0; i < ff->total_tracks; i++) {
1289 free(ff->track[i]->stsz_table);
1290 free(ff->track[i]->stts_sample_count);
1291 free(ff->track[i]->stts_sample_delta);
1292 free(ff->track[i]->stsc_first_chunk);
1293 free(ff->track[i]->stsc_samples_per_chunk);
1294 free(ff->track[i]->stsc_sample_desc_index);
1295 free(ff->track[i]->stco_chunk_offset);
1296 free(ff->track[i]->decoderConfig);
1297 free(ff->track[i]->ctts_sample_count);
1298 free(ff->track[i]->ctts_sample_offset);
1303 mp4ff_tag_delete(&(ff->tags));
1307 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1308 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1310 int32_t total_entries = 0;
1311 int32_t chunk2entry;
1312 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1316 if (f->track[track] == NULL) {
1320 total_entries = f->track[track]->stsc_entry_count;
1327 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1328 *chunk = chunk2 - chunk1;
1329 range_samples = *chunk * chunk1samples;
1331 if (sample < total + range_samples)
1334 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1337 if (chunk2entry < total_entries) {
1339 total += range_samples;
1341 } while (chunk2entry < total_entries);
1344 *chunk = (sample - total) / chunk1samples + chunk1;
1348 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1353 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1354 const int32_t chunk)
1356 const mp4ff_track_t *p_track = f->track[track];
1358 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1359 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1361 } else if (p_track->stco_entry_count) {
1362 return p_track->stco_chunk_offset[chunk - 1];
1370 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1371 const int32_t chunk_sample, const int32_t sample)
1374 const mp4ff_track_t *p_track = f->track[track];
1376 if (p_track->stsz_sample_size) {
1377 return (sample - chunk_sample) * p_track->stsz_sample_size;
1379 if (sample >= p_track->stsz_sample_count)
1382 for (i = chunk_sample, total = 0; i < sample; i++) {
1383 total += p_track->stsz_table[i];
1389 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1390 const int32_t sample)
1392 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1394 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1396 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1397 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1398 track, chunk_sample, sample);
1399 return chunk_offset2;
1402 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1403 const int32_t sample)
1405 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1406 mp4ff_set_position(f, offset);
1409 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1411 const mp4ff_track_t *t = f->track[track];
1413 if (t->stsz_sample_size != 0)
1414 return t->stsz_sample_size;
1415 return t->stsz_table[sample];
1418 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1420 return f->track[track]->sampleRate;
1423 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1425 return f->track[track]->channelCount;
1428 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1433 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1434 total += f->track[track]->stts_sample_count[i];
1439 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1441 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1455 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1457 return f->tags.count;
1460 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1461 char **item, char **value)
1463 if (index >= f->tags.count) {
1468 *item = para_strdup(f->tags.tags[index].item);
1469 *value = para_strdup(f->tags.tags[index].value);
1474 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1477 uint32_t remaining = size;
1478 uint64_t atom_offset = base;
1483 mp4ff_set_position(f, atom_offset);
1487 atom_size = mp4ff_read_int32(f);
1488 if (atom_size > remaining || atom_size < 8)
1490 mp4ff_read_data(f, atom_name, 4);
1492 if (!memcmp(atom_name, name, 4)) {
1493 mp4ff_set_position(f, atom_offset);
1497 remaining -= atom_size;
1498 atom_offset += atom_size;
1502 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1503 const char *name, uint32_t extraheaders, const char *name_inside)
1505 uint64_t first_base = (uint64_t) (-1);
1506 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1508 uint64_t mybase = mp4ff_position(f);
1509 uint32_t mysize = mp4ff_read_int32(f);
1511 if (first_base == (uint64_t) (-1))
1512 first_base = mybase;
1514 if (mysize < 8 + extraheaders)
1517 if (find_atom (f, mybase + (8 + extraheaders),
1518 mysize - (8 + extraheaders), name_inside)) {
1519 mp4ff_set_position(f, mybase);
1523 if (size <= mysize) {
1530 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1532 mp4ff_set_position(f, first_base);
1545 #define stricmp strcasecmp
1547 static membuffer *membuffer_create(void)
1549 const unsigned initial_size = 256;
1551 membuffer *buf = para_malloc(sizeof (membuffer));
1552 buf->data = para_malloc(initial_size);
1554 buf->allocated = initial_size;
1555 buf->error = buf->data == 0 ? 1 : 0;
1560 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1562 unsigned dest_size = buf->written + bytes;
1566 if (dest_size > buf->allocated) {
1568 buf->allocated <<= 1;
1569 } while (dest_size > buf->allocated);
1572 void *newptr = realloc(buf->data, buf->allocated);
1584 memcpy((char *) buf->data + buf->written, ptr, bytes);
1585 buf->written += bytes;
1589 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1591 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1594 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1596 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1597 return membuffer_write(buf, temp, 2);
1600 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1602 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1603 (uint8_t) (data >> 8), (uint8_t) data };
1604 return membuffer_write(buf, temp, 4);
1607 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1608 uint32_t index, uint32_t total)
1610 membuffer_write_int32(buf,
1611 8 /*atom header */ + 8 /*data atom header */ +
1612 8 /*flags + reserved */ + 8 /*actual data */ );
1613 membuffer_write_atom_name(buf, name);
1614 membuffer_write_int32(buf,
1615 8 /*data atom header */ +
1616 8 /*flags + reserved */ + 8 /*actual data */ );
1617 membuffer_write_atom_name(buf, "data");
1618 membuffer_write_int32(buf, 0); //flags
1619 membuffer_write_int32(buf, 0); //reserved
1620 membuffer_write_int16(buf, 0);
1621 membuffer_write_int16(buf, (uint16_t) index); //track number
1622 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1623 membuffer_write_int16(buf, 0);
1626 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1629 membuffer_write_int32(buf,
1630 8 /*atom header */ + 8 /*data atom header */ +
1631 8 /*flags + reserved */ + 2 /*actual data */ );
1632 membuffer_write_atom_name(buf, name);
1633 membuffer_write_int32(buf,
1634 8 /*data atom header */ +
1635 8 /*flags + reserved */ + 2 /*actual data */ );
1636 membuffer_write_atom_name(buf, "data");
1637 membuffer_write_int32(buf, 0); //flags
1638 membuffer_write_int32(buf, 0); //reserved
1639 membuffer_write_int16(buf, value); //value
1642 static uint32_t myatoi(const char *param)
1644 return param ? atoi(param) : 0;
1647 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1650 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1651 if (!stricmp(genrestr, ID3v1GenreList[n]))
1662 static stdmeta_entry stdmetas[] = {
1663 {"\xA9" "nam", "title"},
1664 {"\xA9" "ART", "artist"},
1665 {"\xA9" "wrt", "writer"},
1666 {"\xA9" "alb", "album"},
1667 {"\xA9" "day", "date"},
1668 {"\xA9" "too", "tool"},
1669 {"\xA9" "cmt", "comment"},
1670 {"cpil", "compilation"},
1672 {"aART", "album_artist"},
1675 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1678 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1679 if (!stricmp(name, stdmetas[n].name))
1680 return stdmetas[n].atom;
1685 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1690 /* special check for compilation flag */
1691 if (strcmp(name, "cpil") == 0) {
1695 membuffer_write_int32(buf,
1696 8 /*atom header */ + 8 /*data atom header */ +
1697 8 /*flags + reserved */ + strlen(value));
1698 membuffer_write_atom_name(buf, name);
1699 membuffer_write_int32(buf,
1700 8 /*data atom header */ +
1701 8 /*flags + reserved */ + strlen(value));
1702 membuffer_write_atom_name(buf, "data");
1703 membuffer_write_int32(buf, flags); //flags
1704 membuffer_write_int32(buf, 0); //reserved
1705 membuffer_write(buf, value, strlen(value));
1708 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1711 membuffer_write_int32(buf,
1712 8 /*atom header */ +
1713 0x1C /*weirdo itunes atom */ +
1714 12 /*name atom header */ + strlen(name) +
1715 16 /*data atom header + flags */ + strlen(value));
1716 membuffer_write_atom_name(buf, "----");
1717 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1718 membuffer_write_atom_name(buf, "mean");
1719 membuffer_write_int32(buf, 0);
1720 membuffer_write(buf, "com.apple.iTunes", 16);
1721 membuffer_write_int32(buf, 12 + strlen(name));
1722 membuffer_write_atom_name(buf, "name");
1723 membuffer_write_int32(buf, 0);
1724 membuffer_write(buf, name, strlen(name));
1725 membuffer_write_int32(buf,
1726 8 /*data atom header */ +
1727 8 /*flags + reserved */ + strlen(value));
1728 membuffer_write_atom_name(buf, "data");
1729 membuffer_write_int32(buf, 1); //flags
1730 membuffer_write_int32(buf, 0); //reserved
1731 membuffer_write(buf, value, strlen(value));
1734 static unsigned membuffer_error(const membuffer * buf)
1739 static void membuffer_free(membuffer * buf)
1745 static unsigned membuffer_get_size(const membuffer * buf)
1747 return buf->written;
1750 static void *membuffer_detach(membuffer * buf)
1757 ret = realloc(buf->data, buf->written);
1768 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1769 uint32_t * out_size)
1771 membuffer *buf = membuffer_create();
1773 char *mask = para_calloc(data->count);
1775 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1776 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1777 const char *genre_ptr = 0, *tempo_ptr = 0;
1778 for (metaptr = 0; metaptr < data->count; metaptr++) {
1779 mp4ff_tag_t *tag = &data->tags[metaptr];
1780 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1781 if (tracknumber_ptr == 0)
1782 tracknumber_ptr = tag->value;
1784 } else if (!stricmp(tag->item, "totaltracks")) {
1785 if (totaltracks_ptr == 0)
1786 totaltracks_ptr = tag->value;
1788 } else if (!stricmp(tag->item, "discnumber")
1789 || !stricmp(tag->item, "disc")) {
1790 if (discnumber_ptr == 0)
1791 discnumber_ptr = tag->value;
1793 } else if (!stricmp(tag->item, "totaldiscs")) {
1794 if (totaldiscs_ptr == 0)
1795 totaldiscs_ptr = tag->value;
1797 } else if (!stricmp(tag->item, "genre")) {
1799 genre_ptr = tag->value;
1801 } else if (!stricmp(tag->item, "tempo")) {
1803 tempo_ptr = tag->value;
1809 if (tracknumber_ptr)
1810 membuffer_write_track_tag(buf, "trkn",
1811 myatoi(tracknumber_ptr),
1812 myatoi(totaltracks_ptr));
1814 membuffer_write_track_tag(buf, "disk",
1815 myatoi(discnumber_ptr),
1816 myatoi(totaldiscs_ptr));
1818 membuffer_write_int16_tag(buf, "tmpo",
1819 (uint16_t) myatoi(tempo_ptr));
1822 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1824 membuffer_write_std_tag(buf, "©gen",
1827 membuffer_write_int16_tag(buf, "gnre",
1832 for (metaptr = 0; metaptr < data->count; metaptr++) {
1833 if (!mask[metaptr]) {
1834 mp4ff_tag_t *tag = &data->tags[metaptr];
1835 const char *std_meta_atom = find_standard_meta(tag->item);
1836 if (std_meta_atom) {
1837 membuffer_write_std_tag(buf, std_meta_atom,
1840 membuffer_write_custom_tag(buf, tag->item,
1848 if (membuffer_error(buf)) {
1849 membuffer_free(buf);
1853 *out_size = membuffer_get_size(buf);
1854 *out_buffer = membuffer_detach(buf);
1855 membuffer_free(buf);
1860 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1863 membuffer_write_int32(buf, size + 8);
1864 membuffer_write_atom_name(buf, name);
1865 membuffer_write(buf, data, size);
1868 static void *membuffer_get_ptr(const membuffer * buf)
1873 static void membuffer_set_error(membuffer * buf)
1878 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1884 oldsize = membuffer_get_size(buf);
1885 if (membuffer_write(buf, 0, bytes) != bytes)
1888 bufptr = membuffer_get_ptr(buf);
1892 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1894 membuffer_set_error(buf);
1901 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1902 uint32_t * out_size)
1908 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1911 buf = membuffer_create();
1913 membuffer_write_int32(buf, 0);
1914 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1917 *out_size = membuffer_get_size(buf);
1918 *out_buffer = membuffer_detach(buf);
1919 membuffer_free(buf);
1923 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1924 uint32_t * out_size)
1930 if (!create_meta(data, &meta_buffer, &meta_size))
1933 buf = membuffer_create();
1935 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1939 *out_size = membuffer_get_size(buf);
1940 *out_buffer = membuffer_detach(buf);
1941 membuffer_free(buf);
1945 static uint32_t fix_byte_order_32(uint32_t src)
1948 uint32_t a, b, c, d;
1951 memcpy(data, &src, sizeof (src));
1952 a = (uint8_t) data[0];
1953 b = (uint8_t) data[1];
1954 c = (uint8_t) data[2];
1955 d = (uint8_t) data[3];
1957 result = (a << 24) | (b << 16) | (c << 8) | d;
1958 return (uint32_t) result;
1961 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1962 void **out_buffer, uint32_t * out_size)
1964 uint64_t total_base = f->moov_offset + 8;
1965 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1967 uint64_t udta_offset, meta_offset, ilst_offset;
1968 uint32_t udta_size, meta_size, ilst_size;
1970 uint32_t new_ilst_size;
1971 void *new_ilst_buffer;
1976 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1978 void *new_udta_buffer;
1979 uint32_t new_udta_size;
1980 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1983 buf = membuffer_create();
1984 mp4ff_set_position(f, total_base);
1985 membuffer_transfer_from_file(buf, f, total_size);
1987 membuffer_write_atom(buf, "udta", new_udta_size,
1990 free(new_udta_buffer);
1992 *out_size = membuffer_get_size(buf);
1993 *out_buffer = membuffer_detach(buf);
1994 membuffer_free(buf);
1997 udta_offset = mp4ff_position(f);
1998 udta_size = mp4ff_read_int32(f);
1999 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2001 void *new_meta_buffer;
2002 uint32_t new_meta_size;
2003 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2006 buf = membuffer_create();
2007 mp4ff_set_position(f, total_base);
2008 membuffer_transfer_from_file(buf, f,
2009 (uint32_t)(udta_offset - total_base));
2011 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2012 membuffer_write_atom_name(buf, "udta");
2013 membuffer_transfer_from_file(buf, f, udta_size);
2015 membuffer_write_atom(buf, "meta", new_meta_size,
2017 free(new_meta_buffer);
2019 *out_size = membuffer_get_size(buf);
2020 *out_buffer = membuffer_detach(buf);
2021 membuffer_free(buf);
2024 meta_offset = mp4ff_position(f);
2025 meta_size = mp4ff_read_int32(f);
2026 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2027 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2028 ilst_offset = mp4ff_position(f);
2029 ilst_size = mp4ff_read_int32(f);
2031 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2034 size_delta = new_ilst_size - (ilst_size - 8);
2036 *out_size = total_size + size_delta;
2037 *out_buffer = para_malloc(*out_size);
2038 p_out = (uint8_t *) * out_buffer;
2040 mp4ff_set_position(f, total_base);
2041 mp4ff_read_data(f, p_out,
2042 (uint32_t) (udta_offset - total_base));
2043 p_out += (uint32_t) (udta_offset - total_base);
2044 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2046 mp4ff_read_data(f, p_out, 4);
2048 mp4ff_read_data(f, p_out,
2049 (uint32_t) (meta_offset - udta_offset - 8));
2050 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2051 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2053 mp4ff_read_data(f, p_out, 4);
2055 mp4ff_read_data(f, p_out,
2056 (uint32_t) (ilst_offset - meta_offset - 8));
2057 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2058 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2060 mp4ff_read_data(f, p_out, 4);
2063 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2064 p_out += new_ilst_size;
2066 mp4ff_set_position(f, ilst_offset + ilst_size);
2067 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2068 - (ilst_offset - total_base) - ilst_size));
2070 free(new_ilst_buffer);
2075 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2079 result = f->stream->write(f->stream->user_data, data, size);
2081 f->current_position += size;
2086 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2089 uint32_t a, b, c, d;
2092 *(uint32_t *) temp = data;
2093 a = (uint8_t) temp[0];
2094 b = (uint8_t) temp[1];
2095 c = (uint8_t) temp[2];
2096 d = (uint8_t) temp[3];
2098 result = (a << 24) | (b << 16) | (c << 8) | d;
2100 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2103 static int32_t mp4ff_truncate(mp4ff_t * f)
2105 return f->stream->truncate(f->stream->user_data);
2108 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2110 void *new_moov_data;
2111 uint32_t new_moov_size;
2113 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2115 mp4ff_set_position(ff, 0);
2119 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2124 /* copy moov atom to end of the file */
2125 if (ff->last_atom != ATOM_MOOV) {
2126 char *free_data = "free";
2128 /* rename old moov to free */
2129 mp4ff_set_position(ff, ff->moov_offset + 4);
2130 mp4ff_write_data(ff, free_data, 4);
2132 mp4ff_set_position(ff, ff->file_size);
2133 mp4ff_write_int32(ff, new_moov_size + 8);
2134 mp4ff_write_data(ff, "moov", 4);
2135 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2137 mp4ff_set_position(ff, ff->moov_offset);
2138 mp4ff_write_int32(ff, new_moov_size + 8);
2139 mp4ff_write_data(ff, "moov", 4);
2140 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2149 /* find a metadata item by name */
2150 /* returns 0 if item found, 1 if no such item */
2151 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2156 for (i = 0; i < f->tags.count; i++) {
2157 if (!stricmp(f->tags.tags[i].item, item)) {
2158 *value = para_strdup(f->tags.tags[i].value);
2169 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2171 return mp4ff_meta_find_by_name(f, "artist", value);
2174 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2176 return mp4ff_meta_find_by_name(f, "title", value);
2179 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2181 return mp4ff_meta_find_by_name(f, "date", value);
2184 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2186 return mp4ff_meta_find_by_name(f, "album", value);
2189 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2191 return mp4ff_meta_find_by_name(f, "comment", value);