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 if (f->track[f->total_tracks - 1]->decoderConfig)
648 free(f->track[f->total_tracks - 1]->decoderConfig);
649 f->track[f->total_tracks - 1]->decoderConfig =
650 para_malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
651 if (f->track[f->total_tracks - 1]->decoderConfig) {
652 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
653 f->track[f->total_tracks -
654 1]->decoderConfigLen);
656 /* will skip the remainder of the atom */
659 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
662 uint8_t atom_type = 0;
663 uint8_t header_size = 0;
665 if (f->total_tracks == 0)
668 for (i = 0; i < 6; i++) {
669 mp4ff_read_char(f); /* reserved */
671 /* data_reference_index */ mp4ff_read_int16(f);
673 mp4ff_read_int32(f); /* reserved */
674 mp4ff_read_int32(f); /* reserved */
676 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
677 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
682 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
686 mp4ff_atom_read_header(f, &atom_type, &header_size);
687 if (atom_type == ATOM_ESDS) {
694 static int32_t mp4ff_read_stsd(mp4ff_t * f)
697 uint8_t header_size = 0;
700 if (f->total_tracks == 0)
703 mp4ff_read_char(f); /* version */
704 mp4ff_read_int24(f); /* flags */
706 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
708 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) { /* CVE-2017-9253 */
709 uint64_t skip = mp4ff_position(f);
711 uint8_t atom_type = 0;
712 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
715 if (atom_type == ATOM_MP4A) {
716 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
718 } else if (atom_type == ATOM_MP4V) {
719 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
720 } else if (atom_type == ATOM_MP4S) {
721 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
723 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
726 mp4ff_set_position(f, skip);
732 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
736 mp4ff_read_char(f); /* version */
737 mp4ff_read_int24(f); /* flags */
738 /* creation_time */ mp4ff_read_int32(f);
739 /* modification_time */ mp4ff_read_int32(f);
740 f->time_scale = mp4ff_read_int32(f);
741 f->duration = mp4ff_read_int32(f);
742 /* preferred_rate */ mp4ff_read_int32(f);
743 /*mp4ff_read_fixed32(f); */
744 /* preferred_volume */ mp4ff_read_int16(f);
745 /*mp4ff_read_fixed16(f); */
746 for (i = 0; i < 10; i++) {
747 /* reserved */ mp4ff_read_char(f);
749 for (i = 0; i < 9; i++) {
750 mp4ff_read_int32(f); /* matrix */
752 /* preview_time */ mp4ff_read_int32(f);
753 /* preview_duration */ mp4ff_read_int32(f);
754 /* poster_time */ mp4ff_read_int32(f);
755 /* selection_time */ mp4ff_read_int32(f);
756 /* selection_duration */ mp4ff_read_int32(f);
757 /* current_time */ mp4ff_read_int32(f);
758 /* next_track_id */ mp4ff_read_int32(f);
763 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
764 const char *value, int32_t len)
766 void *backup = (void *) tags->tags;
768 if (!item || (item && !*item) || !value)
771 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
772 (tags->count + 1) * sizeof (mp4ff_tag_t));
778 tags->tags[tags->count].item = strdup(item);
779 tags->tags[tags->count].len = len;
781 tags->tags[tags->count].value = para_malloc(len + 1);
782 memcpy(tags->tags[tags->count].value, value, len);
783 tags->tags[tags->count].value[len] = 0;
785 tags->tags[tags->count].value = strdup(value);
788 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
789 if (!tags->tags[tags->count].item)
790 free(tags->tags[tags->count].item);
791 if (!tags->tags[tags->count].value)
792 free(tags->tags[tags->count].value);
793 tags->tags[tags->count].item = NULL;
794 tags->tags[tags->count].value = NULL;
795 tags->tags[tags->count].len = 0;
804 static const char *ID3v1GenreList[] = {
805 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
806 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
807 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
808 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
809 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
810 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
811 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
812 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
813 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
814 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
815 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
816 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
817 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
818 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
819 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
820 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
821 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
822 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
823 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
824 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
825 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
826 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
827 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
828 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
829 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
830 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
831 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
832 "Anime", "JPop", "SynthPop",
835 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
837 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
838 return ID3v1GenreList[idx - 1];
844 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
846 char *str = para_malloc(length + 1);
847 if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
855 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
857 static char *tag_names[] = {
858 "unknown", "title", "artist", "writer", "album",
859 "date", "tool", "comment", "genre", "track",
860 "disc", "compilation", "genre", "tempo", "cover",
861 "album_artist", "contentgroup", "lyrics", "description",
862 "network", "show", "episodename",
863 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
864 "sortwriter", "sortshow",
865 "season", "episode", "podcast"
900 case ATOM_COMPILATION:
912 case ATOM_ALBUM_ARTIST:
915 case ATOM_CONTENTGROUP:
921 case ATOM_DESCRIPTION:
930 case ATOM_EPISODENAME:
939 case ATOM_SORTARTIST:
942 case ATOM_SORTALBUMARTIST:
945 case ATOM_SORTWRITER:
965 *name = strdup(tag_names[tag_idx]);
970 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
974 uint8_t header_size = 0;
975 uint64_t subsize, sumsize = 0;
981 while (sumsize < size && !f->stream->read_error) { /* CVE-2017-9222 */
983 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
984 destpos = mp4ff_position(f) + subsize - header_size;
986 if (atom_type == ATOM_DATA) {
987 mp4ff_read_char(f); /* version */
988 mp4ff_read_int24(f); /* flags */
989 mp4ff_read_int32(f); /* reserved */
991 /* some need special attention */
992 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
993 if (subsize - header_size >= 8 + 2) {
994 uint16_t val = mp4ff_read_int16(f);
996 if (parent_atom_type == ATOM_TEMPO) {
1001 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
1003 const char *temp = mp4ff_meta_index_to_genre(val);
1005 mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1010 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1011 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) + /* version + flags + reserved */
1012 +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1013 +sizeof (uint16_t) /* track / disc */
1014 +sizeof (uint16_t)) /* totaltracks / totaldiscs */) {
1015 uint16_t index, total;
1017 mp4ff_read_int16(f);
1018 index = mp4ff_read_int16(f);
1019 total = mp4ff_read_int16(f);
1020 if (parent_atom_type == ATOM_TRACK)
1021 mp4ff_read_int16(f);
1023 sprintf(temp, "%d", index);
1024 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1025 "track" : "disc", temp, -1);
1029 mp4ff_tag_add_field(& (f-> tags),
1030 parent_atom_type == ATOM_TRACK?
1031 "totaltracks" : "totaldiscs", temp, -1);
1040 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1041 len = (uint32_t) (subsize - (header_size + 8));
1043 } else if (atom_type == ATOM_NAME) {
1045 mp4ff_read_char(f); /* version */
1046 mp4ff_read_int24(f); /* flags */
1049 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1052 mp4ff_set_position(f, destpos);
1060 mp4ff_set_metadata_name(parent_atom_type, &name);
1062 mp4ff_tag_add_field(&(f->tags), name, data, len);
1071 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1076 if (f->total_tracks == 0)
1079 version = mp4ff_read_int32(f);
1081 mp4ff_read_int64(f); //creation-time
1082 mp4ff_read_int64(f); //modification-time
1083 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1084 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f); //duration
1085 } else //version == 0
1089 mp4ff_read_int32(f); //creation-time
1090 mp4ff_read_int32(f); //modification-time
1091 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1092 temp = mp4ff_read_int32(f);
1093 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1095 mp4ff_read_int16(f);
1096 mp4ff_read_int16(f);
1100 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1102 uint64_t subsize, sumsize = 0;
1104 uint8_t header_size = 0;
1106 while (sumsize < size) {
1107 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1110 mp4ff_parse_tag(f, atom_type,
1111 (uint32_t) (subsize - header_size));
1118 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1120 uint64_t subsize, sumsize = 0;
1122 uint8_t header_size = 0;
1124 mp4ff_read_char(f); /* version */
1125 mp4ff_read_int24(f); /* flags */
1127 while (sumsize < (size - (header_size + 4))) {
1128 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1129 if (subsize <= header_size + 4)
1131 if (atom_type == ATOM_ILST) {
1132 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1134 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1142 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1143 const uint8_t atom_type)
1145 uint64_t dest_position = mp4ff_position(f) + size - 8;
1146 if (atom_type == ATOM_STSZ) {
1147 /* sample size box */
1149 } else if (atom_type == ATOM_STTS) {
1150 /* time to sample box */
1152 } else if (atom_type == ATOM_CTTS) {
1153 /* composition offset box */
1155 } else if (atom_type == ATOM_STSC) {
1156 /* sample to chunk box */
1158 } else if (atom_type == ATOM_STCO) {
1159 /* chunk offset box */
1161 } else if (atom_type == ATOM_STSD) {
1162 /* sample description box */
1164 } else if (atom_type == ATOM_MVHD) {
1165 /* movie header box */
1167 } else if (atom_type == ATOM_MDHD) {
1170 } else if (atom_type == ATOM_META) {
1171 /* iTunes Metadata box */
1172 mp4ff_read_meta(f, size);
1175 mp4ff_set_position(f, dest_position);
1179 /* parse atoms that are sub atoms of other atoms */
1180 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1183 uint8_t atom_type = 0;
1184 uint64_t counted_size = 0;
1185 uint8_t header_size = 0;
1187 while (counted_size < total_size) {
1188 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1189 counted_size += size;
1191 /* check for end of file */
1195 /* we're starting to read a new track, update index,
1196 * so that all data and tables get written in the right place
1198 if (atom_type == ATOM_TRAK) {
1202 /* parse subatoms */
1203 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1204 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1205 } else if (atom_type < SUBATOMIC) {
1206 parse_sub_atoms(f, size - header_size, meta_only);
1208 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1215 /* parse root atoms */
1216 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1219 uint8_t atom_type = 0;
1220 uint8_t header_size = 0;
1223 f->stream->read_error = 0;
1226 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1227 f->file_size += size;
1228 f->last_atom = atom_type;
1230 if (atom_type == ATOM_MOOV && size > header_size) {
1231 f->moov_offset = mp4ff_position(f) - header_size;
1232 f->moov_size = size;
1235 /* parse subatoms */
1236 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1237 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1238 } else if (atom_type < SUBATOMIC) {
1239 parse_sub_atoms(f, size - header_size, meta_only);
1241 /* skip this atom */
1242 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1249 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1250 unsigned char **ppBuf, unsigned int *pBufSize)
1252 if (track >= f->total_tracks) {
1258 if (f->track[track]->decoderConfig == NULL
1259 || f->track[track]->decoderConfigLen == 0) {
1263 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1264 memcpy(*ppBuf, f->track[track]->decoderConfig,
1265 f->track[track]->decoderConfigLen);
1266 *pBufSize = f->track[track]->decoderConfigLen;
1270 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1272 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1286 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1290 for (i = 0; i < tags->count; i++) {
1291 if (tags->tags[i].item)
1292 free(tags->tags[i].item);
1293 if (tags->tags[i].value)
1294 free(tags->tags[i].value);
1306 void mp4ff_close(mp4ff_t * ff)
1310 for (i = 0; i < ff->total_tracks; i++) {
1312 if (ff->track[i]->stsz_table)
1313 free(ff->track[i]->stsz_table);
1314 if (ff->track[i]->stts_sample_count)
1315 free(ff->track[i]->stts_sample_count);
1316 if (ff->track[i]->stts_sample_delta)
1317 free(ff->track[i]->stts_sample_delta);
1318 if (ff->track[i]->stsc_first_chunk)
1319 free(ff->track[i]->stsc_first_chunk);
1320 if (ff->track[i]->stsc_samples_per_chunk)
1321 free(ff->track[i]->stsc_samples_per_chunk);
1322 if (ff->track[i]->stsc_sample_desc_index)
1323 free(ff->track[i]->stsc_sample_desc_index);
1324 if (ff->track[i]->stco_chunk_offset)
1325 free(ff->track[i]->stco_chunk_offset);
1326 if (ff->track[i]->decoderConfig)
1327 free(ff->track[i]->decoderConfig);
1328 if (ff->track[i]->ctts_sample_count)
1329 free(ff->track[i]->ctts_sample_count);
1330 if (ff->track[i]->ctts_sample_offset)
1331 free(ff->track[i]->ctts_sample_offset);
1336 mp4ff_tag_delete(&(ff->tags));
1342 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1343 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1345 int32_t total_entries = 0;
1346 int32_t chunk2entry;
1347 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1351 if (f->track[track] == NULL) {
1355 total_entries = f->track[track]->stsc_entry_count;
1362 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1363 *chunk = chunk2 - chunk1;
1364 range_samples = *chunk * chunk1samples;
1366 if (sample < total + range_samples)
1369 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1372 if (chunk2entry < total_entries) {
1374 total += range_samples;
1376 } while (chunk2entry < total_entries);
1379 *chunk = (sample - total) / chunk1samples + chunk1;
1383 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1388 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1389 const int32_t chunk)
1391 const mp4ff_track_t *p_track = f->track[track];
1393 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1394 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1396 } else if (p_track->stco_entry_count) {
1397 return p_track->stco_chunk_offset[chunk - 1];
1405 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1406 const int32_t chunk_sample, const int32_t sample)
1409 const mp4ff_track_t *p_track = f->track[track];
1411 if (p_track->stsz_sample_size) {
1412 return (sample - chunk_sample) * p_track->stsz_sample_size;
1414 if (sample >= p_track->stsz_sample_count)
1417 for (i = chunk_sample, total = 0; i < sample; i++) {
1418 total += p_track->stsz_table[i];
1424 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1425 const int32_t sample)
1427 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1429 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1431 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1432 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1433 track, chunk_sample, sample);
1434 return chunk_offset2;
1437 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1438 const int32_t sample)
1440 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1441 mp4ff_set_position(f, offset);
1444 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1446 const mp4ff_track_t *t = f->track[track];
1448 if (t->stsz_sample_size != 0)
1449 return t->stsz_sample_size;
1450 return t->stsz_table[sample];
1453 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1455 return f->track[track]->sampleRate;
1458 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1460 return f->track[track]->channelCount;
1463 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1468 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1469 total += f->track[track]->stts_sample_count[i];
1474 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1476 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1490 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1492 return f->tags.count;
1495 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1496 char **item, char **value)
1498 if (index >= f->tags.count) {
1503 *item = strdup(f->tags.tags[index].item);
1504 *value = strdup(f->tags.tags[index].value);
1509 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1512 uint32_t remaining = size;
1513 uint64_t atom_offset = base;
1518 mp4ff_set_position(f, atom_offset);
1522 atom_size = mp4ff_read_int32(f);
1523 if (atom_size > remaining || atom_size < 8)
1525 mp4ff_read_data(f, atom_name, 4);
1527 if (!memcmp(atom_name, name, 4)) {
1528 mp4ff_set_position(f, atom_offset);
1532 remaining -= atom_size;
1533 atom_offset += atom_size;
1537 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1538 const char *name, uint32_t extraheaders, const char *name_inside)
1540 uint64_t first_base = (uint64_t) (-1);
1541 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1543 uint64_t mybase = mp4ff_position(f);
1544 uint32_t mysize = mp4ff_read_int32(f);
1546 if (first_base == (uint64_t) (-1))
1547 first_base = mybase;
1549 if (mysize < 8 + extraheaders)
1552 if (find_atom (f, mybase + (8 + extraheaders),
1553 mysize - (8 + extraheaders), name_inside)) {
1554 mp4ff_set_position(f, mybase);
1558 if (size <= mysize) {
1565 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1567 mp4ff_set_position(f, first_base);
1580 #define stricmp strcasecmp
1582 static membuffer *membuffer_create(void)
1584 const unsigned initial_size = 256;
1586 membuffer *buf = para_malloc(sizeof (membuffer));
1587 buf->data = para_malloc(initial_size);
1589 buf->allocated = initial_size;
1590 buf->error = buf->data == 0 ? 1 : 0;
1595 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1597 unsigned dest_size = buf->written + bytes;
1601 if (dest_size > buf->allocated) {
1603 buf->allocated <<= 1;
1604 } while (dest_size > buf->allocated);
1607 void *newptr = realloc(buf->data, buf->allocated);
1619 memcpy((char *) buf->data + buf->written, ptr, bytes);
1620 buf->written += bytes;
1624 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1626 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1629 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1631 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1632 return membuffer_write(buf, temp, 2);
1635 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1637 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1638 (uint8_t) (data >> 8), (uint8_t) data };
1639 return membuffer_write(buf, temp, 4);
1642 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1643 uint32_t index, uint32_t total)
1645 membuffer_write_int32(buf,
1646 8 /*atom header */ + 8 /*data atom header */ +
1647 8 /*flags + reserved */ + 8 /*actual data */ );
1648 membuffer_write_atom_name(buf, name);
1649 membuffer_write_int32(buf,
1650 8 /*data atom header */ +
1651 8 /*flags + reserved */ + 8 /*actual data */ );
1652 membuffer_write_atom_name(buf, "data");
1653 membuffer_write_int32(buf, 0); //flags
1654 membuffer_write_int32(buf, 0); //reserved
1655 membuffer_write_int16(buf, 0);
1656 membuffer_write_int16(buf, (uint16_t) index); //track number
1657 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1658 membuffer_write_int16(buf, 0);
1661 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1664 membuffer_write_int32(buf,
1665 8 /*atom header */ + 8 /*data atom header */ +
1666 8 /*flags + reserved */ + 2 /*actual data */ );
1667 membuffer_write_atom_name(buf, name);
1668 membuffer_write_int32(buf,
1669 8 /*data atom header */ +
1670 8 /*flags + reserved */ + 2 /*actual data */ );
1671 membuffer_write_atom_name(buf, "data");
1672 membuffer_write_int32(buf, 0); //flags
1673 membuffer_write_int32(buf, 0); //reserved
1674 membuffer_write_int16(buf, value); //value
1677 static uint32_t myatoi(const char *param)
1679 return param ? atoi(param) : 0;
1682 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1685 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1686 if (!stricmp(genrestr, ID3v1GenreList[n]))
1697 static stdmeta_entry stdmetas[] = {
1698 {"\xA9" "nam", "title"},
1699 {"\xA9" "ART", "artist"},
1700 {"\xA9" "wrt", "writer"},
1701 {"\xA9" "alb", "album"},
1702 {"\xA9" "day", "date"},
1703 {"\xA9" "too", "tool"},
1704 {"\xA9" "cmt", "comment"},
1705 {"cpil", "compilation"},
1707 {"aART", "album_artist"},
1710 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1713 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1714 if (!stricmp(name, stdmetas[n].name))
1715 return stdmetas[n].atom;
1720 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1725 /* special check for compilation flag */
1726 if (strcmp(name, "cpil") == 0) {
1730 membuffer_write_int32(buf,
1731 8 /*atom header */ + 8 /*data atom header */ +
1732 8 /*flags + reserved */ + strlen(value));
1733 membuffer_write_atom_name(buf, name);
1734 membuffer_write_int32(buf,
1735 8 /*data atom header */ +
1736 8 /*flags + reserved */ + strlen(value));
1737 membuffer_write_atom_name(buf, "data");
1738 membuffer_write_int32(buf, flags); //flags
1739 membuffer_write_int32(buf, 0); //reserved
1740 membuffer_write(buf, value, strlen(value));
1743 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1746 membuffer_write_int32(buf,
1747 8 /*atom header */ +
1748 0x1C /*weirdo itunes atom */ +
1749 12 /*name atom header */ + strlen(name) +
1750 16 /*data atom header + flags */ + strlen(value));
1751 membuffer_write_atom_name(buf, "----");
1752 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1753 membuffer_write_atom_name(buf, "mean");
1754 membuffer_write_int32(buf, 0);
1755 membuffer_write(buf, "com.apple.iTunes", 16);
1756 membuffer_write_int32(buf, 12 + strlen(name));
1757 membuffer_write_atom_name(buf, "name");
1758 membuffer_write_int32(buf, 0);
1759 membuffer_write(buf, name, strlen(name));
1760 membuffer_write_int32(buf,
1761 8 /*data atom header */ +
1762 8 /*flags + reserved */ + strlen(value));
1763 membuffer_write_atom_name(buf, "data");
1764 membuffer_write_int32(buf, 1); //flags
1765 membuffer_write_int32(buf, 0); //reserved
1766 membuffer_write(buf, value, strlen(value));
1769 static unsigned membuffer_error(const membuffer * buf)
1774 static void membuffer_free(membuffer * buf)
1781 static unsigned membuffer_get_size(const membuffer * buf)
1783 return buf->written;
1786 static void *membuffer_detach(membuffer * buf)
1793 ret = realloc(buf->data, buf->written);
1804 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1805 uint32_t * out_size)
1807 membuffer *buf = membuffer_create();
1809 char *mask = para_calloc(data->count);
1811 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1812 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1813 const char *genre_ptr = 0, *tempo_ptr = 0;
1814 for (metaptr = 0; metaptr < data->count; metaptr++) {
1815 mp4ff_tag_t *tag = &data->tags[metaptr];
1816 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1817 if (tracknumber_ptr == 0)
1818 tracknumber_ptr = tag->value;
1820 } else if (!stricmp(tag->item, "totaltracks")) {
1821 if (totaltracks_ptr == 0)
1822 totaltracks_ptr = tag->value;
1824 } else if (!stricmp(tag->item, "discnumber")
1825 || !stricmp(tag->item, "disc")) {
1826 if (discnumber_ptr == 0)
1827 discnumber_ptr = tag->value;
1829 } else if (!stricmp(tag->item, "totaldiscs")) {
1830 if (totaldiscs_ptr == 0)
1831 totaldiscs_ptr = tag->value;
1833 } else if (!stricmp(tag->item, "genre")) {
1835 genre_ptr = tag->value;
1837 } else if (!stricmp(tag->item, "tempo")) {
1839 tempo_ptr = tag->value;
1845 if (tracknumber_ptr)
1846 membuffer_write_track_tag(buf, "trkn",
1847 myatoi(tracknumber_ptr),
1848 myatoi(totaltracks_ptr));
1850 membuffer_write_track_tag(buf, "disk",
1851 myatoi(discnumber_ptr),
1852 myatoi(totaldiscs_ptr));
1854 membuffer_write_int16_tag(buf, "tmpo",
1855 (uint16_t) myatoi(tempo_ptr));
1858 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1860 membuffer_write_std_tag(buf, "©gen",
1863 membuffer_write_int16_tag(buf, "gnre",
1868 for (metaptr = 0; metaptr < data->count; metaptr++) {
1869 if (!mask[metaptr]) {
1870 mp4ff_tag_t *tag = &data->tags[metaptr];
1871 const char *std_meta_atom = find_standard_meta(tag->item);
1872 if (std_meta_atom) {
1873 membuffer_write_std_tag(buf, std_meta_atom,
1876 membuffer_write_custom_tag(buf, tag->item,
1884 if (membuffer_error(buf)) {
1885 membuffer_free(buf);
1889 *out_size = membuffer_get_size(buf);
1890 *out_buffer = membuffer_detach(buf);
1891 membuffer_free(buf);
1896 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1899 membuffer_write_int32(buf, size + 8);
1900 membuffer_write_atom_name(buf, name);
1901 membuffer_write(buf, data, size);
1904 static void *membuffer_get_ptr(const membuffer * buf)
1909 static void membuffer_set_error(membuffer * buf)
1914 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1920 oldsize = membuffer_get_size(buf);
1921 if (membuffer_write(buf, 0, bytes) != bytes)
1924 bufptr = membuffer_get_ptr(buf);
1928 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1930 membuffer_set_error(buf);
1937 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1938 uint32_t * out_size)
1944 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1947 buf = membuffer_create();
1949 membuffer_write_int32(buf, 0);
1950 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1953 *out_size = membuffer_get_size(buf);
1954 *out_buffer = membuffer_detach(buf);
1955 membuffer_free(buf);
1959 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1960 uint32_t * out_size)
1966 if (!create_meta(data, &meta_buffer, &meta_size))
1969 buf = membuffer_create();
1971 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1975 *out_size = membuffer_get_size(buf);
1976 *out_buffer = membuffer_detach(buf);
1977 membuffer_free(buf);
1981 static uint32_t fix_byte_order_32(uint32_t src)
1984 uint32_t a, b, c, d;
1987 memcpy(data, &src, sizeof (src));
1988 a = (uint8_t) data[0];
1989 b = (uint8_t) data[1];
1990 c = (uint8_t) data[2];
1991 d = (uint8_t) data[3];
1993 result = (a << 24) | (b << 16) | (c << 8) | d;
1994 return (uint32_t) result;
1997 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1998 void **out_buffer, uint32_t * out_size)
2000 uint64_t total_base = f->moov_offset + 8;
2001 uint32_t total_size = (uint32_t) (f->moov_size - 8);
2003 uint64_t udta_offset, meta_offset, ilst_offset;
2004 uint32_t udta_size, meta_size, ilst_size;
2006 uint32_t new_ilst_size;
2007 void *new_ilst_buffer;
2012 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2014 void *new_udta_buffer;
2015 uint32_t new_udta_size;
2016 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2019 buf = membuffer_create();
2020 mp4ff_set_position(f, total_base);
2021 membuffer_transfer_from_file(buf, f, total_size);
2023 membuffer_write_atom(buf, "udta", new_udta_size,
2026 free(new_udta_buffer);
2028 *out_size = membuffer_get_size(buf);
2029 *out_buffer = membuffer_detach(buf);
2030 membuffer_free(buf);
2033 udta_offset = mp4ff_position(f);
2034 udta_size = mp4ff_read_int32(f);
2035 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2037 void *new_meta_buffer;
2038 uint32_t new_meta_size;
2039 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2042 buf = membuffer_create();
2043 mp4ff_set_position(f, total_base);
2044 membuffer_transfer_from_file(buf, f,
2045 (uint32_t)(udta_offset - total_base));
2047 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2048 membuffer_write_atom_name(buf, "udta");
2049 membuffer_transfer_from_file(buf, f, udta_size);
2051 membuffer_write_atom(buf, "meta", new_meta_size,
2053 free(new_meta_buffer);
2055 *out_size = membuffer_get_size(buf);
2056 *out_buffer = membuffer_detach(buf);
2057 membuffer_free(buf);
2060 meta_offset = mp4ff_position(f);
2061 meta_size = mp4ff_read_int32(f);
2062 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2063 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2064 ilst_offset = mp4ff_position(f);
2065 ilst_size = mp4ff_read_int32(f);
2067 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2070 size_delta = new_ilst_size - (ilst_size - 8);
2072 *out_size = total_size + size_delta;
2073 *out_buffer = para_malloc(*out_size);
2074 p_out = (uint8_t *) * out_buffer;
2076 mp4ff_set_position(f, total_base);
2077 mp4ff_read_data(f, p_out,
2078 (uint32_t) (udta_offset - total_base));
2079 p_out += (uint32_t) (udta_offset - total_base);
2080 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2082 mp4ff_read_data(f, p_out, 4);
2084 mp4ff_read_data(f, p_out,
2085 (uint32_t) (meta_offset - udta_offset - 8));
2086 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2087 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2089 mp4ff_read_data(f, p_out, 4);
2091 mp4ff_read_data(f, p_out,
2092 (uint32_t) (ilst_offset - meta_offset - 8));
2093 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2094 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2096 mp4ff_read_data(f, p_out, 4);
2099 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2100 p_out += new_ilst_size;
2102 mp4ff_set_position(f, ilst_offset + ilst_size);
2103 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2104 - (ilst_offset - total_base) - ilst_size));
2106 free(new_ilst_buffer);
2111 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2115 result = f->stream->write(f->stream->user_data, data, size);
2117 f->current_position += size;
2122 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2125 uint32_t a, b, c, d;
2128 *(uint32_t *) temp = data;
2129 a = (uint8_t) temp[0];
2130 b = (uint8_t) temp[1];
2131 c = (uint8_t) temp[2];
2132 d = (uint8_t) temp[3];
2134 result = (a << 24) | (b << 16) | (c << 8) | d;
2136 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2139 static int32_t mp4ff_truncate(mp4ff_t * f)
2141 return f->stream->truncate(f->stream->user_data);
2144 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2146 void *new_moov_data;
2147 uint32_t new_moov_size;
2149 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2151 mp4ff_set_position(ff, 0);
2155 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2160 /* copy moov atom to end of the file */
2161 if (ff->last_atom != ATOM_MOOV) {
2162 char *free_data = "free";
2164 /* rename old moov to free */
2165 mp4ff_set_position(ff, ff->moov_offset + 4);
2166 mp4ff_write_data(ff, free_data, 4);
2168 mp4ff_set_position(ff, ff->file_size);
2169 mp4ff_write_int32(ff, new_moov_size + 8);
2170 mp4ff_write_data(ff, "moov", 4);
2171 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2173 mp4ff_set_position(ff, ff->moov_offset);
2174 mp4ff_write_int32(ff, new_moov_size + 8);
2175 mp4ff_write_data(ff, "moov", 4);
2176 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2185 /* find a metadata item by name */
2186 /* returns 0 if item found, 1 if no such item */
2187 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2192 for (i = 0; i < f->tags.count; i++) {
2193 if (!stricmp(f->tags.tags[i].item, item)) {
2194 *value = strdup(f->tags.tags[i].value);
2205 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2207 return mp4ff_meta_find_by_name(f, "artist", value);
2210 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2212 return mp4ff_meta_find_by_name(f, "title", value);
2215 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2217 return mp4ff_meta_find_by_name(f, "date", value);
2220 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2222 return mp4ff_meta_find_by_name(f, "album", value);
2225 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2227 return mp4ff_meta_find_by_name(f, "comment", value);