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 uint32_t min_body_size(const uint8_t atom_type)
962 return sizeof (char) /* version */
963 + sizeof(uint8_t) * 3 /* flags */
964 + sizeof(uint32_t) /* reserved */
965 + sizeof(uint16_t) /* leading uint16_t */
966 + sizeof(uint16_t) /* track */
967 + sizeof(uint16_t); /* totaltracks */
969 return sizeof (char) /* version */
970 + sizeof(uint8_t) * 3 /* flags */
971 + sizeof(uint32_t) /* reserved */
972 + sizeof(uint16_t) /* disc */
973 + sizeof(uint16_t); /* totaldiscs */
974 default: assert(false);
978 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent,
982 uint8_t header_size = 0;
983 uint64_t subsize, sumsize;
992 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
993 mp4ff_set_position(f, destpos), sumsize += subsize
995 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
996 destpos = mp4ff_position(f) + subsize - header_size;
999 if (atom_type == ATOM_NAME) {
1000 mp4ff_read_char(f); /* version */
1001 mp4ff_read_int24(f); /* flags */
1003 name = mp4ff_read_string(f, subsize - (header_size + 4));
1006 if (atom_type != ATOM_DATA)
1008 mp4ff_read_char(f); /* version */
1009 mp4ff_read_int24(f); /* flags */
1010 mp4ff_read_int32(f); /* reserved */
1012 /* some need special attention */
1013 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1015 if (subsize - header_size < min_body_size(parent))
1017 val = mp4ff_read_int16(f);
1018 if (parent == ATOM_TEMPO) {
1020 sprintf(temp, "%.5u BPM", val);
1021 mp4ff_tag_add_field(&(f-> tags), "tempo",
1024 const char *tmp = mp4ff_meta_index_to_genre(val);
1026 mp4ff_tag_add_field (&(f->tags),
1030 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1031 uint16_t index, total;
1033 if (subsize - header_size < min_body_size(parent))
1035 mp4ff_read_int16(f);
1036 index = mp4ff_read_int16(f);
1037 total = mp4ff_read_int16(f);
1038 if (parent == ATOM_TRACK)
1039 mp4ff_read_int16(f);
1040 sprintf(temp, "%d", index);
1041 mp4ff_tag_add_field(&(f->tags), parent == ATOM_TRACK?
1042 "track" : "disc", temp, -1);
1044 sprintf(temp, "%d", total);
1045 mp4ff_tag_add_field(& (f-> tags),
1046 parent == ATOM_TRACK?
1047 "totaltracks" : "totaldiscs", temp, -1);
1052 data = mp4ff_read_string(f, subsize - (header_size + 8));
1053 len = subsize - (header_size + 8);
1059 mp4ff_set_metadata_name(parent , &name);
1061 mp4ff_tag_add_field(&(f->tags), name, data, len);
1070 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1075 if (f->total_tracks == 0)
1078 version = mp4ff_read_int32(f);
1080 mp4ff_read_int64(f); //creation-time
1081 mp4ff_read_int64(f); //modification-time
1082 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1083 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1084 } else //version == 0
1088 mp4ff_read_int32(f); //creation-time
1089 mp4ff_read_int32(f); //modification-time
1090 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1091 temp = mp4ff_read_int32(f);
1092 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1094 mp4ff_read_int16(f);
1095 mp4ff_read_int16(f);
1099 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1101 uint64_t subsize, sumsize = 0;
1103 uint8_t header_size = 0;
1105 while (sumsize < size) {
1106 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1109 mp4ff_parse_tag(f, atom_type,
1110 (uint32_t) (subsize - header_size));
1117 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1119 uint64_t subsize, sumsize = 0;
1121 uint8_t header_size = 0;
1123 mp4ff_read_char(f); /* version */
1124 mp4ff_read_int24(f); /* flags */
1126 while (sumsize < (size - (header_size + 4))) {
1127 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1128 if (subsize <= header_size + 4)
1130 if (atom_type == ATOM_ILST) {
1131 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1133 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1141 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1142 const uint8_t atom_type)
1144 uint64_t dest_position = mp4ff_position(f) + size - 8;
1145 if (atom_type == ATOM_STSZ) {
1146 /* sample size box */
1148 } else if (atom_type == ATOM_STTS) {
1149 /* time to sample box */
1151 } else if (atom_type == ATOM_CTTS) {
1152 /* composition offset box */
1154 } else if (atom_type == ATOM_STSC) {
1155 /* sample to chunk box */
1157 } else if (atom_type == ATOM_STCO) {
1158 /* chunk offset box */
1160 } else if (atom_type == ATOM_STSD) {
1161 /* sample description box */
1163 } else if (atom_type == ATOM_MVHD) {
1164 /* movie header box */
1166 } else if (atom_type == ATOM_MDHD) {
1169 } else if (atom_type == ATOM_META) {
1170 /* iTunes Metadata box */
1171 mp4ff_read_meta(f, size);
1174 mp4ff_set_position(f, dest_position);
1178 /* parse atoms that are sub atoms of other atoms */
1179 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1182 uint8_t atom_type = 0;
1183 uint64_t counted_size = 0;
1184 uint8_t header_size = 0;
1186 while (counted_size < total_size) {
1187 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1188 counted_size += size;
1190 /* check for end of file */
1194 /* we're starting to read a new track, update index,
1195 * so that all data and tables get written in the right place
1197 if (atom_type == ATOM_TRAK) {
1201 /* parse subatoms */
1202 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1203 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1204 } else if (atom_type < SUBATOMIC) {
1205 parse_sub_atoms(f, size - header_size, meta_only);
1207 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1214 /* parse root atoms */
1215 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1218 uint8_t atom_type = 0;
1219 uint8_t header_size = 0;
1222 f->stream->read_error = 0;
1225 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1226 f->file_size += size;
1227 f->last_atom = atom_type;
1229 if (atom_type == ATOM_MOOV && size > header_size) {
1230 f->moov_offset = mp4ff_position(f) - header_size;
1231 f->moov_size = size;
1234 /* parse subatoms */
1235 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1236 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1237 } else if (atom_type < SUBATOMIC) {
1238 parse_sub_atoms(f, size - header_size, meta_only);
1240 /* skip this atom */
1241 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1248 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1249 unsigned char **ppBuf, unsigned int *pBufSize)
1251 if (track >= f->total_tracks) {
1257 if (f->track[track]->decoderConfig == NULL
1258 || f->track[track]->decoderConfigLen == 0) {
1262 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1263 memcpy(*ppBuf, f->track[track]->decoderConfig,
1264 f->track[track]->decoderConfigLen);
1265 *pBufSize = f->track[track]->decoderConfigLen;
1269 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1271 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1285 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1289 for (i = 0; i < tags->count; i++) {
1290 free(tags->tags[i].item);
1291 free(tags->tags[i].value);
1300 void mp4ff_close(mp4ff_t * ff)
1304 for (i = 0; i < ff->total_tracks; i++) {
1306 free(ff->track[i]->stsz_table);
1307 free(ff->track[i]->stts_sample_count);
1308 free(ff->track[i]->stts_sample_delta);
1309 free(ff->track[i]->stsc_first_chunk);
1310 free(ff->track[i]->stsc_samples_per_chunk);
1311 free(ff->track[i]->stsc_sample_desc_index);
1312 free(ff->track[i]->stco_chunk_offset);
1313 free(ff->track[i]->decoderConfig);
1314 free(ff->track[i]->ctts_sample_count);
1315 free(ff->track[i]->ctts_sample_offset);
1320 mp4ff_tag_delete(&(ff->tags));
1324 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1325 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1327 int32_t total_entries = 0;
1328 int32_t chunk2entry;
1329 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1333 if (f->track[track] == NULL) {
1337 total_entries = f->track[track]->stsc_entry_count;
1344 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1345 *chunk = chunk2 - chunk1;
1346 range_samples = *chunk * chunk1samples;
1348 if (sample < total + range_samples)
1351 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1354 if (chunk2entry < total_entries) {
1356 total += range_samples;
1358 } while (chunk2entry < total_entries);
1361 *chunk = (sample - total) / chunk1samples + chunk1;
1365 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1370 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1371 const int32_t chunk)
1373 const mp4ff_track_t *p_track = f->track[track];
1375 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1376 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1378 } else if (p_track->stco_entry_count) {
1379 return p_track->stco_chunk_offset[chunk - 1];
1387 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1388 const int32_t chunk_sample, const int32_t sample)
1391 const mp4ff_track_t *p_track = f->track[track];
1393 if (p_track->stsz_sample_size) {
1394 return (sample - chunk_sample) * p_track->stsz_sample_size;
1396 if (sample >= p_track->stsz_sample_count)
1399 for (i = chunk_sample, total = 0; i < sample; i++) {
1400 total += p_track->stsz_table[i];
1406 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1407 const int32_t sample)
1409 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1411 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1413 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1414 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1415 track, chunk_sample, sample);
1416 return chunk_offset2;
1419 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1420 const int32_t sample)
1422 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1423 mp4ff_set_position(f, offset);
1426 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1428 const mp4ff_track_t *t = f->track[track];
1430 if (t->stsz_sample_size != 0)
1431 return t->stsz_sample_size;
1432 return t->stsz_table[sample];
1435 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1437 return f->track[track]->sampleRate;
1440 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1442 return f->track[track]->channelCount;
1445 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1450 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1451 total += f->track[track]->stts_sample_count[i];
1456 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1458 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1472 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1474 return f->tags.count;
1477 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1478 char **item, char **value)
1480 if (index >= f->tags.count) {
1485 *item = para_strdup(f->tags.tags[index].item);
1486 *value = para_strdup(f->tags.tags[index].value);
1491 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1494 uint32_t remaining = size;
1495 uint64_t atom_offset = base;
1500 mp4ff_set_position(f, atom_offset);
1504 atom_size = mp4ff_read_int32(f);
1505 if (atom_size > remaining || atom_size < 8)
1507 mp4ff_read_data(f, atom_name, 4);
1509 if (!memcmp(atom_name, name, 4)) {
1510 mp4ff_set_position(f, atom_offset);
1514 remaining -= atom_size;
1515 atom_offset += atom_size;
1519 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1520 const char *name, uint32_t extraheaders, const char *name_inside)
1522 uint64_t first_base = (uint64_t) (-1);
1523 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1525 uint64_t mybase = mp4ff_position(f);
1526 uint32_t mysize = mp4ff_read_int32(f);
1528 if (first_base == (uint64_t) (-1))
1529 first_base = mybase;
1531 if (mysize < 8 + extraheaders)
1534 if (find_atom (f, mybase + (8 + extraheaders),
1535 mysize - (8 + extraheaders), name_inside)) {
1536 mp4ff_set_position(f, mybase);
1540 if (size <= mysize) {
1547 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1549 mp4ff_set_position(f, first_base);
1562 #define stricmp strcasecmp
1564 static membuffer *membuffer_create(void)
1566 const unsigned initial_size = 256;
1568 membuffer *buf = para_malloc(sizeof (membuffer));
1569 buf->data = para_malloc(initial_size);
1571 buf->allocated = initial_size;
1572 buf->error = buf->data == 0 ? 1 : 0;
1577 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1579 unsigned dest_size = buf->written + bytes;
1583 if (dest_size > buf->allocated) {
1585 buf->allocated <<= 1;
1586 } while (dest_size > buf->allocated);
1589 void *newptr = realloc(buf->data, buf->allocated);
1601 memcpy((char *) buf->data + buf->written, ptr, bytes);
1602 buf->written += bytes;
1606 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1608 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1611 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1613 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1614 return membuffer_write(buf, temp, 2);
1617 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1619 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1620 (uint8_t) (data >> 8), (uint8_t) data };
1621 return membuffer_write(buf, temp, 4);
1624 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1625 uint32_t index, uint32_t total)
1627 membuffer_write_int32(buf,
1628 8 /*atom header */ + 8 /*data atom header */ +
1629 8 /*flags + reserved */ + 8 /*actual data */ );
1630 membuffer_write_atom_name(buf, name);
1631 membuffer_write_int32(buf,
1632 8 /*data atom header */ +
1633 8 /*flags + reserved */ + 8 /*actual data */ );
1634 membuffer_write_atom_name(buf, "data");
1635 membuffer_write_int32(buf, 0); //flags
1636 membuffer_write_int32(buf, 0); //reserved
1637 membuffer_write_int16(buf, 0);
1638 membuffer_write_int16(buf, (uint16_t) index); //track number
1639 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1640 membuffer_write_int16(buf, 0);
1643 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1646 membuffer_write_int32(buf,
1647 8 /*atom header */ + 8 /*data atom header */ +
1648 8 /*flags + reserved */ + 2 /*actual data */ );
1649 membuffer_write_atom_name(buf, name);
1650 membuffer_write_int32(buf,
1651 8 /*data atom header */ +
1652 8 /*flags + reserved */ + 2 /*actual data */ );
1653 membuffer_write_atom_name(buf, "data");
1654 membuffer_write_int32(buf, 0); //flags
1655 membuffer_write_int32(buf, 0); //reserved
1656 membuffer_write_int16(buf, value); //value
1659 static uint32_t myatoi(const char *param)
1661 return param ? atoi(param) : 0;
1664 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1667 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1668 if (!stricmp(genrestr, ID3v1GenreList[n]))
1679 static stdmeta_entry stdmetas[] = {
1680 {"\xA9" "nam", "title"},
1681 {"\xA9" "ART", "artist"},
1682 {"\xA9" "wrt", "writer"},
1683 {"\xA9" "alb", "album"},
1684 {"\xA9" "day", "date"},
1685 {"\xA9" "too", "tool"},
1686 {"\xA9" "cmt", "comment"},
1687 {"cpil", "compilation"},
1689 {"aART", "album_artist"},
1692 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1695 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1696 if (!stricmp(name, stdmetas[n].name))
1697 return stdmetas[n].atom;
1702 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1707 /* special check for compilation flag */
1708 if (strcmp(name, "cpil") == 0) {
1712 membuffer_write_int32(buf,
1713 8 /*atom header */ + 8 /*data atom header */ +
1714 8 /*flags + reserved */ + strlen(value));
1715 membuffer_write_atom_name(buf, name);
1716 membuffer_write_int32(buf,
1717 8 /*data atom header */ +
1718 8 /*flags + reserved */ + strlen(value));
1719 membuffer_write_atom_name(buf, "data");
1720 membuffer_write_int32(buf, flags); //flags
1721 membuffer_write_int32(buf, 0); //reserved
1722 membuffer_write(buf, value, strlen(value));
1725 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1728 membuffer_write_int32(buf,
1729 8 /*atom header */ +
1730 0x1C /*weirdo itunes atom */ +
1731 12 /*name atom header */ + strlen(name) +
1732 16 /*data atom header + flags */ + strlen(value));
1733 membuffer_write_atom_name(buf, "----");
1734 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1735 membuffer_write_atom_name(buf, "mean");
1736 membuffer_write_int32(buf, 0);
1737 membuffer_write(buf, "com.apple.iTunes", 16);
1738 membuffer_write_int32(buf, 12 + strlen(name));
1739 membuffer_write_atom_name(buf, "name");
1740 membuffer_write_int32(buf, 0);
1741 membuffer_write(buf, name, strlen(name));
1742 membuffer_write_int32(buf,
1743 8 /*data atom header */ +
1744 8 /*flags + reserved */ + strlen(value));
1745 membuffer_write_atom_name(buf, "data");
1746 membuffer_write_int32(buf, 1); //flags
1747 membuffer_write_int32(buf, 0); //reserved
1748 membuffer_write(buf, value, strlen(value));
1751 static unsigned membuffer_error(const membuffer * buf)
1756 static void membuffer_free(membuffer * buf)
1762 static unsigned membuffer_get_size(const membuffer * buf)
1764 return buf->written;
1767 static void *membuffer_detach(membuffer * buf)
1774 ret = realloc(buf->data, buf->written);
1785 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1786 uint32_t * out_size)
1788 membuffer *buf = membuffer_create();
1790 char *mask = para_calloc(data->count);
1792 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1793 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1794 const char *genre_ptr = 0, *tempo_ptr = 0;
1795 for (metaptr = 0; metaptr < data->count; metaptr++) {
1796 mp4ff_tag_t *tag = &data->tags[metaptr];
1797 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1798 if (tracknumber_ptr == 0)
1799 tracknumber_ptr = tag->value;
1801 } else if (!stricmp(tag->item, "totaltracks")) {
1802 if (totaltracks_ptr == 0)
1803 totaltracks_ptr = tag->value;
1805 } else if (!stricmp(tag->item, "discnumber")
1806 || !stricmp(tag->item, "disc")) {
1807 if (discnumber_ptr == 0)
1808 discnumber_ptr = tag->value;
1810 } else if (!stricmp(tag->item, "totaldiscs")) {
1811 if (totaldiscs_ptr == 0)
1812 totaldiscs_ptr = tag->value;
1814 } else if (!stricmp(tag->item, "genre")) {
1816 genre_ptr = tag->value;
1818 } else if (!stricmp(tag->item, "tempo")) {
1820 tempo_ptr = tag->value;
1826 if (tracknumber_ptr)
1827 membuffer_write_track_tag(buf, "trkn",
1828 myatoi(tracknumber_ptr),
1829 myatoi(totaltracks_ptr));
1831 membuffer_write_track_tag(buf, "disk",
1832 myatoi(discnumber_ptr),
1833 myatoi(totaldiscs_ptr));
1835 membuffer_write_int16_tag(buf, "tmpo",
1836 (uint16_t) myatoi(tempo_ptr));
1839 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1841 membuffer_write_std_tag(buf, "©gen",
1844 membuffer_write_int16_tag(buf, "gnre",
1849 for (metaptr = 0; metaptr < data->count; metaptr++) {
1850 if (!mask[metaptr]) {
1851 mp4ff_tag_t *tag = &data->tags[metaptr];
1852 const char *std_meta_atom = find_standard_meta(tag->item);
1853 if (std_meta_atom) {
1854 membuffer_write_std_tag(buf, std_meta_atom,
1857 membuffer_write_custom_tag(buf, tag->item,
1865 if (membuffer_error(buf)) {
1866 membuffer_free(buf);
1870 *out_size = membuffer_get_size(buf);
1871 *out_buffer = membuffer_detach(buf);
1872 membuffer_free(buf);
1877 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1880 membuffer_write_int32(buf, size + 8);
1881 membuffer_write_atom_name(buf, name);
1882 membuffer_write(buf, data, size);
1885 static void *membuffer_get_ptr(const membuffer * buf)
1890 static void membuffer_set_error(membuffer * buf)
1895 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1901 oldsize = membuffer_get_size(buf);
1902 if (membuffer_write(buf, 0, bytes) != bytes)
1905 bufptr = membuffer_get_ptr(buf);
1909 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1911 membuffer_set_error(buf);
1918 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1919 uint32_t * out_size)
1925 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1928 buf = membuffer_create();
1930 membuffer_write_int32(buf, 0);
1931 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1934 *out_size = membuffer_get_size(buf);
1935 *out_buffer = membuffer_detach(buf);
1936 membuffer_free(buf);
1940 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1941 uint32_t * out_size)
1947 if (!create_meta(data, &meta_buffer, &meta_size))
1950 buf = membuffer_create();
1952 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1956 *out_size = membuffer_get_size(buf);
1957 *out_buffer = membuffer_detach(buf);
1958 membuffer_free(buf);
1962 static uint32_t fix_byte_order_32(uint32_t src)
1965 uint32_t a, b, c, d;
1968 memcpy(data, &src, sizeof (src));
1969 a = (uint8_t) data[0];
1970 b = (uint8_t) data[1];
1971 c = (uint8_t) data[2];
1972 d = (uint8_t) data[3];
1974 result = (a << 24) | (b << 16) | (c << 8) | d;
1975 return (uint32_t) result;
1978 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1979 void **out_buffer, uint32_t * out_size)
1981 uint64_t total_base = f->moov_offset + 8;
1982 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1984 uint64_t udta_offset, meta_offset, ilst_offset;
1985 uint32_t udta_size, meta_size, ilst_size;
1987 uint32_t new_ilst_size;
1988 void *new_ilst_buffer;
1993 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1995 void *new_udta_buffer;
1996 uint32_t new_udta_size;
1997 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2000 buf = membuffer_create();
2001 mp4ff_set_position(f, total_base);
2002 membuffer_transfer_from_file(buf, f, total_size);
2004 membuffer_write_atom(buf, "udta", new_udta_size,
2007 free(new_udta_buffer);
2009 *out_size = membuffer_get_size(buf);
2010 *out_buffer = membuffer_detach(buf);
2011 membuffer_free(buf);
2014 udta_offset = mp4ff_position(f);
2015 udta_size = mp4ff_read_int32(f);
2016 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2018 void *new_meta_buffer;
2019 uint32_t new_meta_size;
2020 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2023 buf = membuffer_create();
2024 mp4ff_set_position(f, total_base);
2025 membuffer_transfer_from_file(buf, f,
2026 (uint32_t)(udta_offset - total_base));
2028 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2029 membuffer_write_atom_name(buf, "udta");
2030 membuffer_transfer_from_file(buf, f, udta_size);
2032 membuffer_write_atom(buf, "meta", new_meta_size,
2034 free(new_meta_buffer);
2036 *out_size = membuffer_get_size(buf);
2037 *out_buffer = membuffer_detach(buf);
2038 membuffer_free(buf);
2041 meta_offset = mp4ff_position(f);
2042 meta_size = mp4ff_read_int32(f);
2043 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2044 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2045 ilst_offset = mp4ff_position(f);
2046 ilst_size = mp4ff_read_int32(f);
2048 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2051 size_delta = new_ilst_size - (ilst_size - 8);
2053 *out_size = total_size + size_delta;
2054 *out_buffer = para_malloc(*out_size);
2055 p_out = (uint8_t *) * out_buffer;
2057 mp4ff_set_position(f, total_base);
2058 mp4ff_read_data(f, p_out,
2059 (uint32_t) (udta_offset - total_base));
2060 p_out += (uint32_t) (udta_offset - total_base);
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) (meta_offset - udta_offset - 8));
2067 p_out += (uint32_t) (meta_offset - udta_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);
2072 mp4ff_read_data(f, p_out,
2073 (uint32_t) (ilst_offset - meta_offset - 8));
2074 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2075 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2077 mp4ff_read_data(f, p_out, 4);
2080 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2081 p_out += new_ilst_size;
2083 mp4ff_set_position(f, ilst_offset + ilst_size);
2084 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2085 - (ilst_offset - total_base) - ilst_size));
2087 free(new_ilst_buffer);
2092 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2096 result = f->stream->write(f->stream->user_data, data, size);
2098 f->current_position += size;
2103 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2106 uint32_t a, b, c, d;
2109 *(uint32_t *) temp = data;
2110 a = (uint8_t) temp[0];
2111 b = (uint8_t) temp[1];
2112 c = (uint8_t) temp[2];
2113 d = (uint8_t) temp[3];
2115 result = (a << 24) | (b << 16) | (c << 8) | d;
2117 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2120 static int32_t mp4ff_truncate(mp4ff_t * f)
2122 return f->stream->truncate(f->stream->user_data);
2125 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2127 void *new_moov_data;
2128 uint32_t new_moov_size;
2130 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2132 mp4ff_set_position(ff, 0);
2136 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2141 /* copy moov atom to end of the file */
2142 if (ff->last_atom != ATOM_MOOV) {
2143 char *free_data = "free";
2145 /* rename old moov to free */
2146 mp4ff_set_position(ff, ff->moov_offset + 4);
2147 mp4ff_write_data(ff, free_data, 4);
2149 mp4ff_set_position(ff, ff->file_size);
2150 mp4ff_write_int32(ff, new_moov_size + 8);
2151 mp4ff_write_data(ff, "moov", 4);
2152 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2154 mp4ff_set_position(ff, ff->moov_offset);
2155 mp4ff_write_int32(ff, new_moov_size + 8);
2156 mp4ff_write_data(ff, "moov", 4);
2157 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2166 /* find a metadata item by name */
2167 /* returns 0 if item found, 1 if no such item */
2168 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2173 for (i = 0; i < f->tags.count; i++) {
2174 if (!stricmp(f->tags.tags[i].item, item)) {
2175 *value = para_strdup(f->tags.tags[i].value);
2186 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2188 return mp4ff_meta_find_by_name(f, "artist", value);
2191 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2193 return mp4ff_meta_find_by_name(f, "title", value);
2196 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2198 return mp4ff_meta_find_by_name(f, "date", value);
2201 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2203 return mp4ff_meta_find_by_name(f, "album", value);
2206 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2208 return mp4ff_meta_find_by_name(f, "comment", value);