2 * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3 * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
12 int32_t mp4ff_total_tracks(const mp4ff_t *f)
14 return f->total_tracks;
17 int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size)
21 result = f->stream->read(f->stream->user_data, data, size);
24 f->stream->read_error++;
26 f->current_position += size;
31 /* parse atom header size */
32 static int32_t mp4ff_atom_get_size(const int8_t *data)
42 result = (a<<24) | (b<<16) | (c<<8) | d;
43 //if (result > 0 && result < 8) result = 8;
45 return (int32_t)result;
48 uint64_t mp4ff_read_int64(mp4ff_t *f)
54 mp4ff_read_data(f, data, 8);
56 for (i = 0; i < 8; i++)
58 result |= ((uint64_t)data[i]) << ((7 - i) * 8);
64 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
65 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1,
66 const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2)
68 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
76 #define TRACK_SYSTEM 3
77 #define TRACK_UNKNOWN 0
79 /* atoms with subatoms */
87 #define ATOM_ILST 8 /* iTunes Metadata list */
89 #define ATOM_ARTIST 10
90 #define ATOM_WRITER 11
94 #define ATOM_COMMENT 15
95 #define ATOM_GENRE1 16
98 #define ATOM_COMPILATION 19
99 #define ATOM_GENRE2 20
100 #define ATOM_TEMPO 21
101 #define ATOM_COVER 22
106 #define SUBATOMIC 128
108 /* atoms without subatoms */
109 #define ATOM_FTYP 129
110 #define ATOM_MDAT 130
111 #define ATOM_MVHD 131
112 #define ATOM_TKHD 132
113 #define ATOM_TREF 133
114 #define ATOM_MDHD 134
115 #define ATOM_VMHD 135
116 #define ATOM_SMHD 136
117 #define ATOM_HMHD 137
118 #define ATOM_STSD 138
119 #define ATOM_STTS 139
120 #define ATOM_STSZ 140
121 #define ATOM_STZ2 141
122 #define ATOM_STCO 142
123 #define ATOM_STSC 143
124 #define ATOM_MP4A 144
125 #define ATOM_MP4V 145
126 #define ATOM_MP4S 146
127 #define ATOM_ESDS 147
128 #define ATOM_META 148 /* iTunes Metadata box */
129 #define ATOM_NAME 149 /* iTunes Metadata name box */
130 #define ATOM_DATA 150 /* iTunes Metadata data box */
131 #define ATOM_CTTS 151
132 #define ATOM_FRMA 152
133 #define ATOM_IVIV 153
134 #define ATOM_PRIV 154
135 #define ATOM_USER 155
137 #define ATOM_ALBUM_ARTIST 157
138 #define ATOM_CONTENTGROUP 158
139 #define ATOM_LYRICS 159
140 #define ATOM_DESCRIPTION 160
141 #define ATOM_NETWORK 161
142 #define ATOM_SHOW 162
143 #define ATOM_EPISODENAME 163
144 #define ATOM_SORTTITLE 164
145 #define ATOM_SORTALBUM 165
146 #define ATOM_SORTARTIST 166
147 #define ATOM_SORTALBUMARTIST 167
148 #define ATOM_SORTWRITER 168
149 #define ATOM_SORTSHOW 169
150 #define ATOM_SEASON 170
151 #define ATOM_EPISODE 171
152 #define ATOM_PODCAST 172
154 #define ATOM_UNKNOWN 255
155 #define ATOM_FREE ATOM_UNKNOWN
156 #define ATOM_SKIP ATOM_UNKNOWN
158 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
160 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
161 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(a,b,c,d, COPYRIGHT_SYMBOL,'n','a','m'))
244 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'A','R','T'))
246 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'w','r','t'))
248 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'a','l','b'))
250 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'d','a','y'))
252 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'t','o','o'))
254 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'c','m','t'))
256 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','e','n'))
258 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','r','p'))
259 return ATOM_CONTENTGROUP;
260 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'l','y','r'))
264 if (mp4ff_atom_compare(a,b,c,d, 'e','d','t','s'))
266 else if (mp4ff_atom_compare(a,b,c,d, 'e','s','d','s'))
268 else if (mp4ff_atom_compare(a,b,c,d, 'f','t','y','p'))
270 else if (mp4ff_atom_compare(a,b,c,d, 'f','r','e','e'))
272 else if (mp4ff_atom_compare(a,b,c,d, 'h','m','h','d'))
274 else if (mp4ff_atom_compare(a,b,c,d, 'v','m','h','d'))
276 else if (mp4ff_atom_compare(a,b,c,d, 'u','d','t','a'))
278 else if (mp4ff_atom_compare(a,b,c,d, 'i','l','s','t'))
280 else if (mp4ff_atom_compare(a,b,c,d, 'n','a','m','e'))
282 else if (mp4ff_atom_compare(a,b,c,d, 'd','a','t','a'))
284 else if (mp4ff_atom_compare(a,b,c,d, 'd','i','s','k'))
286 else if (mp4ff_atom_compare(a,b,c,d, 'g','n','r','e'))
288 else if (mp4ff_atom_compare(a,b,c,d, 'c','o','v','r'))
290 else if (mp4ff_atom_compare(a,b,c,d, 'c','p','i','l'))
291 return ATOM_COMPILATION;
292 else if (mp4ff_atom_compare(a,b,c,d, 'c','t','t','s'))
294 else if (mp4ff_atom_compare(a,b,c,d, 'd','r','m','s'))
296 else if (mp4ff_atom_compare(a,b,c,d, 'f','r','m','a'))
298 else if (mp4ff_atom_compare(a,b,c,d, 'p','r','i','v'))
300 else if (mp4ff_atom_compare(a,b,c,d, 'i','v','i','v'))
302 else if (mp4ff_atom_compare(a,b,c,d, 'u','s','e','r'))
304 else if (mp4ff_atom_compare(a,b,c,d, 'k','e','y',' '))
306 else if (mp4ff_atom_compare(a,b,c,d, 'a','A','R','T'))
307 return ATOM_ALBUM_ARTIST;
308 else if (mp4ff_atom_compare(a,b,c,d, 'd','e','s','c'))
309 return ATOM_DESCRIPTION;
310 else if (mp4ff_atom_compare(a,b,c,d, 'p','c','s','t'))
316 /* read atom header, return atom size, atom size is with header included */
317 uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_size)
321 int8_t atom_header[8];
323 ret = mp4ff_read_data(f, atom_header, 8);
327 size = mp4ff_atom_get_size(atom_header);
330 /* check for 64 bit atom size */
334 size = mp4ff_read_int64(f);
337 //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
339 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
344 int64_t mp4ff_position(const mp4ff_t *f)
346 return f->current_position;
349 static int need_parse_when_meta_only(uint8_t atom_type)
376 int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position)
378 f->stream->seek(f->stream->user_data, position);
379 f->current_position = position;
384 static void mp4ff_track_add(mp4ff_t *f)
388 if (f->total_tracks > MAX_TRACKS)
395 f->track[f->total_tracks - 1] = malloc(sizeof(mp4ff_track_t));
397 memset(f->track[f->total_tracks - 1], 0, sizeof(mp4ff_track_t));
400 uint8_t mp4ff_read_char(mp4ff_t *f)
403 mp4ff_read_data(f, &output, 1);
407 uint32_t mp4ff_read_int24(mp4ff_t *f)
413 mp4ff_read_data(f, data, 3);
414 a = (uint8_t)data[0];
415 b = (uint8_t)data[1];
416 c = (uint8_t)data[2];
418 result = (a<<16) | (b<<8) | c;
419 return (uint32_t)result;
422 uint32_t mp4ff_read_int32(mp4ff_t *f)
428 mp4ff_read_data(f, data, 4);
429 a = (uint8_t)data[0];
430 b = (uint8_t)data[1];
431 c = (uint8_t)data[2];
432 d = (uint8_t)data[3];
434 result = (a<<24) | (b<<16) | (c<<8) | d;
435 return (uint32_t)result;
438 static int32_t mp4ff_read_stsz(mp4ff_t *f)
440 if (f->total_tracks == 0)
443 mp4ff_read_char(f); /* version */
444 mp4ff_read_int24(f); /* flags */
445 f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
446 f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
448 if (f->track[f->total_tracks - 1]->stsz_sample_size == 0)
451 f->track[f->total_tracks - 1]->stsz_table =
452 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsz_sample_count*sizeof(int32_t));
454 if (!f->track[f->total_tracks - 1]->stsz_table)
457 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count && !f->stream->read_error; i++)
459 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
466 static int32_t mp4ff_read_stts(mp4ff_t *f)
469 mp4ff_track_t * p_track;
472 if (f->total_tracks == 0)
475 p_track = f->track[f->total_tracks - 1];
477 if (p_track->stts_entry_count) return 0;
479 mp4ff_read_char(f); /* version */
480 mp4ff_read_int24(f); /* flags */
481 p_track->stts_entry_count = mp4ff_read_int32(f);
483 p_track->stts_sample_count = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
484 p_track->stts_sample_delta = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
486 if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0)
488 if (p_track->stts_sample_count) {free(p_track->stts_sample_count);p_track->stts_sample_count=0;}
489 if (p_track->stts_sample_delta) {free(p_track->stts_sample_delta);p_track->stts_sample_delta=0;}
490 p_track->stts_entry_count = 0;
495 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) /* CVE-2017-9254 */
497 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
498 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
504 static int32_t mp4ff_read_ctts(mp4ff_t *f)
507 mp4ff_track_t * p_track;
509 if (f->total_tracks == 0)
512 p_track = f->track[f->total_tracks - 1];
513 if (p_track->ctts_entry_count) return 0;
515 mp4ff_read_char(f); /* version */
516 mp4ff_read_int24(f); /* flags */
517 p_track->ctts_entry_count = mp4ff_read_int32(f);
519 p_track->ctts_sample_count = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
520 p_track->ctts_sample_offset = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
522 if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0)
524 if (p_track->ctts_sample_count) {free(p_track->ctts_sample_count);p_track->ctts_sample_count=0;}
525 if (p_track->ctts_sample_offset) {free(p_track->ctts_sample_offset);p_track->ctts_sample_offset=0;}
526 p_track->ctts_entry_count = 0;
531 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) /* CVE-2017-9257 */
533 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
534 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
540 static int32_t mp4ff_read_stsc(mp4ff_t *f)
544 if (f->total_tracks == 0)
547 mp4ff_read_char(f); /* version */
548 mp4ff_read_int24(f); /* flags */
549 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
551 f->track[f->total_tracks - 1]->stsc_first_chunk =
552 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
553 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
554 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
555 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
556 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
559 if (!f->track[f->total_tracks - 1]->stsc_first_chunk)
563 if (!f->track[f->total_tracks - 1]->stsc_samples_per_chunk)
565 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
566 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
569 if (!f->track[f->total_tracks - 1]->stsc_sample_desc_index)
571 free(f->track[f->total_tracks - 1]->stsc_first_chunk);
572 f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
573 free(f->track[f->total_tracks - 1]->stsc_samples_per_chunk);
574 f->track[f->total_tracks - 1]->stsc_samples_per_chunk = NULL;
578 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) /* CVE-2017-9255 */
580 f->track[f->total_tracks - 1]->stsc_first_chunk[i] = mp4ff_read_int32(f);
581 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] = mp4ff_read_int32(f);
582 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] = mp4ff_read_int32(f);
588 static int32_t mp4ff_read_stco(mp4ff_t *f)
592 if (f->total_tracks == 0)
595 mp4ff_read_char(f); /* version */
596 mp4ff_read_int24(f); /* flags */
597 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
599 f->track[f->total_tracks - 1]->stco_chunk_offset =
600 (int32_t*)malloc(f->track[f->total_tracks - 1]->stco_entry_count*sizeof(int32_t));
603 if (!f->track[f->total_tracks - 1]->stco_chunk_offset)
606 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) /* CVE-2017-9256 */
608 f->track[f->total_tracks - 1]->stco_chunk_offset[i] = mp4ff_read_int32(f);
614 uint16_t mp4ff_read_int16(mp4ff_t *f)
620 mp4ff_read_data(f, data, 2);
621 a = (uint8_t)data[0];
622 b = (uint8_t)data[1];
625 return (uint16_t)result;
629 uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f)
632 uint8_t numBytes = 0;
637 b = mp4ff_read_char(f);
639 length = (length << 7) | (b & 0x7F);
640 } while ((b & 0x80) && numBytes < 4);
644 static int32_t mp4ff_read_esds(mp4ff_t *f)
649 if (f->total_tracks == 0)
652 mp4ff_read_char(f); /* version */
653 mp4ff_read_int24(f); /* flags */
655 /* get and verify ES_DescrTag */
656 tag = mp4ff_read_char(f);
660 if (mp4ff_read_mp4_descr_length(f) < 5 + 15)
671 /* get and verify DecoderConfigDescrTab */
672 if (mp4ff_read_char(f) != 0x04)
678 temp = mp4ff_read_mp4_descr_length(f);
679 if (temp < 13) return 1;
681 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
682 mp4ff_read_int32(f);//0x15000414 ????
683 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
684 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
686 /* get and verify DecSpecificInfoTag */
687 if (mp4ff_read_char(f) != 0x05)
693 f->track[f->total_tracks - 1]->decoderConfigLen = mp4ff_read_mp4_descr_length(f);
695 if (f->track[f->total_tracks - 1]->decoderConfig)
696 free(f->track[f->total_tracks - 1]->decoderConfig);
697 f->track[f->total_tracks - 1]->decoderConfig = malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
698 if (f->track[f->total_tracks - 1]->decoderConfig)
700 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig, f->track[f->total_tracks - 1]->decoderConfigLen);
702 f->track[f->total_tracks - 1]->decoderConfigLen = 0;
705 /* will skip the remainder of the atom */
708 static int32_t mp4ff_read_mp4a(mp4ff_t *f)
712 uint8_t atom_type = 0;
713 uint8_t header_size = 0;
715 if (f->total_tracks == 0)
718 for (i = 0; i < 6; i++)
720 mp4ff_read_char(f); /* reserved */
722 /* data_reference_index */ mp4ff_read_int16(f);
724 mp4ff_read_int32(f); /* reserved */
725 mp4ff_read_int32(f); /* reserved */
727 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
728 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
733 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
737 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
738 if (atom_type == ATOM_ESDS)
746 static int32_t mp4ff_read_stsd(mp4ff_t *f)
749 uint8_t header_size = 0;
752 if (f->total_tracks == 0)
755 mp4ff_read_char(f); /* version */
756 mp4ff_read_int24(f); /* flags */
758 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
760 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) /* CVE-2017-9253 */
762 uint64_t skip = mp4ff_position(f);
764 uint8_t atom_type = 0;
765 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
768 if (atom_type == ATOM_MP4A)
770 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
772 } else if (atom_type == ATOM_MP4V) {
773 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
774 } else if (atom_type == ATOM_MP4S) {
775 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
777 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
780 mp4ff_set_position(f, skip);
786 static int32_t mp4ff_read_mvhd(mp4ff_t *f)
790 mp4ff_read_char(f); /* version */
791 mp4ff_read_int24(f); /* flags */
792 /* creation_time */ mp4ff_read_int32(f);
793 /* modification_time */ mp4ff_read_int32(f);
794 f->time_scale = mp4ff_read_int32(f);
795 f->duration = mp4ff_read_int32(f);
796 /* preferred_rate */ mp4ff_read_int32(f); /*mp4ff_read_fixed32(f);*/
797 /* preferred_volume */ mp4ff_read_int16(f); /*mp4ff_read_fixed16(f);*/
798 for (i = 0; i < 10; i++)
800 /* reserved */ mp4ff_read_char(f);
802 for (i = 0; i < 9; i++)
804 mp4ff_read_int32(f); /* matrix */
806 /* preview_time */ mp4ff_read_int32(f);
807 /* preview_duration */ mp4ff_read_int32(f);
808 /* poster_time */ mp4ff_read_int32(f);
809 /* selection_time */ mp4ff_read_int32(f);
810 /* selection_duration */ mp4ff_read_int32(f);
811 /* current_time */ mp4ff_read_int32(f);
812 /* next_track_id */ mp4ff_read_int32(f);
817 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, int32_t len)
819 void *backup = (void *)tags->tags;
821 if (!item || (item && !*item) || !value) return 0;
823 tags->tags = (mp4ff_tag_t*)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t));
826 if (backup) free(backup);
829 tags->tags[tags->count].item = strdup(item);
830 tags->tags[tags->count].len = len;
832 tags->tags[tags->count].value = malloc(len + 1);
833 if (tags->tags[tags->count].value != NULL) {
834 memcpy(tags->tags[tags->count].value, value, len);
835 tags->tags[tags->count].value[len] = 0;
839 tags->tags[tags->count].value = strdup(value);
842 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
844 if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
845 if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
846 tags->tags[tags->count].item = NULL;
847 tags->tags[tags->count].value = NULL;
848 tags->tags[tags->count].len = 0;
857 static const char* ID3v1GenreList[] = {
858 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
859 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
860 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
861 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
862 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
863 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
864 "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
865 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock",
866 "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
867 "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
868 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
869 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
870 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
871 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing",
872 "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
873 "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
874 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
875 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
876 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
877 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
878 "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
879 "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
880 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
881 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
882 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
886 const char * mp4ff_meta_index_to_genre(uint32_t idx)
888 if (idx>0 && idx<=sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]))
890 return ID3v1GenreList[idx-1];
898 char * mp4ff_read_string(mp4ff_t * f,uint32_t length)
900 char * str = (char*)malloc(length + 1);
903 if ((uint32_t)mp4ff_read_data(f,str,length)!=length)
916 static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name)
918 static char *tag_names[] = {
919 "unknown", "title", "artist", "writer", "album",
920 "date", "tool", "comment", "genre", "track",
921 "disc", "compilation", "genre", "tempo", "cover",
922 "album_artist", "contentgroup", "lyrics", "description",
923 "network", "show", "episodename",
924 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
925 "sortwriter", "sortshow",
926 "season", "episode", "podcast"
933 case ATOM_TITLE: tag_idx = 1; break;
934 case ATOM_ARTIST: tag_idx = 2; break;
935 case ATOM_WRITER: tag_idx = 3; break;
936 case ATOM_ALBUM: tag_idx = 4; break;
937 case ATOM_DATE: tag_idx = 5; break;
938 case ATOM_TOOL: tag_idx = 6; break;
939 case ATOM_COMMENT: tag_idx = 7; break;
940 case ATOM_GENRE1: tag_idx = 8; break;
941 case ATOM_TRACK: tag_idx = 9; break;
942 case ATOM_DISC: tag_idx = 10; break;
943 case ATOM_COMPILATION: tag_idx = 11; break;
944 case ATOM_GENRE2: tag_idx = 12; break;
945 case ATOM_TEMPO: tag_idx = 13; break;
946 case ATOM_COVER: tag_idx = 14; break;
947 case ATOM_ALBUM_ARTIST: tag_idx = 15; break;
948 case ATOM_CONTENTGROUP: tag_idx = 16; break;
949 case ATOM_LYRICS: tag_idx = 17; break;
950 case ATOM_DESCRIPTION: tag_idx = 18; break;
951 case ATOM_NETWORK: tag_idx = 19; break;
952 case ATOM_SHOW: tag_idx = 20; break;
953 case ATOM_EPISODENAME: tag_idx = 21; break;
954 case ATOM_SORTTITLE: tag_idx = 22; break;
955 case ATOM_SORTALBUM: tag_idx = 23; break;
956 case ATOM_SORTARTIST: tag_idx = 24; break;
957 case ATOM_SORTALBUMARTIST: tag_idx = 25; break;
958 case ATOM_SORTWRITER: tag_idx = 26; break;
959 case ATOM_SORTSHOW: tag_idx = 27; break;
960 case ATOM_SEASON: tag_idx = 28; break;
961 case ATOM_EPISODE: tag_idx = 29; break;
962 case ATOM_PODCAST: tag_idx = 30; break;
963 default: tag_idx = 0; break;
966 *name = strdup(tag_names[tag_idx]);
970 static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size)
973 uint8_t header_size = 0;
974 uint64_t subsize, sumsize = 0;
981 while (sumsize < size && !f->stream->read_error) /* CVE-2017-9222 */
984 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
985 destpos = mp4ff_position(f)+subsize-header_size;
988 if (atom_type == ATOM_DATA)
990 mp4ff_read_char(f); /* version */
991 mp4ff_read_int24(f); /* flags */
992 mp4ff_read_int32(f); /* reserved */
994 /* some need special attention */
995 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
997 if (subsize - header_size >= 8 + 2)
999 uint16_t val = mp4ff_read_int16(f);
1001 if (parent_atom_type == ATOM_TEMPO)
1004 sprintf(temp, "%.5u BPM", val);
1005 mp4ff_tag_add_field(&(f->tags), "tempo", temp, -1);
1009 const char * temp = mp4ff_meta_index_to_genre(val);
1012 mp4ff_tag_add_field(&(f->tags), "genre", temp, -1);
1017 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1018 /* if (!done && subsize - header_size >= 8 + 8) */
1019 /* modified by AJS */
1020 if ( !done && (subsize - header_size) >=
1021 (sizeof(char) + sizeof(uint8_t)*3 + sizeof(uint32_t) + /* version + flags + reserved */
1022 + (parent_atom_type == ATOM_TRACK ? sizeof(uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1023 + sizeof(uint16_t) /* track / disc */
1024 + sizeof(uint16_t)) /* totaltracks / totaldiscs */
1027 uint16_t index,total;
1029 mp4ff_read_int16(f);
1030 index = mp4ff_read_int16(f);
1031 total = mp4ff_read_int16(f);
1032 if (parent_atom_type == ATOM_TRACK)
1033 mp4ff_read_int16(f);
1035 sprintf(temp,"%d",index);
1036 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc", temp, -1);
1039 sprintf(temp,"%d",total);
1040 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs", temp, -1);
1046 if (data) {free(data);data = NULL;}
1047 data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8)));
1048 len = (uint32_t)(subsize-(header_size+8));
1050 } else if (atom_type == ATOM_NAME) {
1053 mp4ff_read_char(f); /* version */
1054 mp4ff_read_int24(f); /* flags */
1055 if (name) free(name);
1056 name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4)));
1059 mp4ff_set_position(f, destpos);
1068 if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name);
1069 if (name) mp4ff_tag_add_field(&(f->tags), name, data, len);
1074 if (name) free(name);
1077 static int32_t mp4ff_read_mdhd(mp4ff_t *f)
1082 if (f->total_tracks == 0)
1085 version = mp4ff_read_int32(f);
1088 mp4ff_read_int64(f);//creation-time
1089 mp4ff_read_int64(f);//modification-time
1090 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
1091 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
1097 mp4ff_read_int32(f);//creation-time
1098 mp4ff_read_int32(f);//modification-time
1099 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
1100 temp = mp4ff_read_int32(f);
1101 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp);
1103 mp4ff_read_int16(f);
1104 mp4ff_read_int16(f);
1108 int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size)
1110 uint64_t subsize, sumsize = 0;
1112 uint8_t header_size = 0;
1114 while (sumsize < size)
1116 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1119 mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size));
1126 static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size)
1128 uint64_t subsize, sumsize = 0;
1130 uint8_t header_size = 0;
1132 mp4ff_read_char(f); /* version */
1133 mp4ff_read_int24(f); /* flags */
1135 while (sumsize < (size-(header_size+4)))
1137 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1138 if (subsize <= header_size+4)
1140 if (atom_type == ATOM_ILST)
1142 mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4)));
1144 mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
1152 int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
1154 uint64_t dest_position = mp4ff_position(f)+size-8;
1155 if (atom_type == ATOM_STSZ)
1157 /* sample size box */
1159 } else if (atom_type == ATOM_STTS) {
1160 /* time to sample box */
1162 } else if (atom_type == ATOM_CTTS) {
1163 /* composition offset box */
1165 } else if (atom_type == ATOM_STSC) {
1166 /* sample to chunk box */
1168 } else if (atom_type == ATOM_STCO) {
1169 /* chunk offset box */
1171 } else if (atom_type == ATOM_STSD) {
1172 /* sample description box */
1174 } else if (atom_type == ATOM_MVHD) {
1175 /* movie header box */
1177 } else if (atom_type == ATOM_MDHD) {
1181 } else if (atom_type == ATOM_META) {
1182 /* iTunes Metadata box */
1183 mp4ff_read_meta(f, size);
1187 mp4ff_set_position(f, dest_position);
1191 /* parse atoms that are sub atoms of other atoms */
1192 int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size,int meta_only)
1195 uint8_t atom_type = 0;
1196 uint64_t counted_size = 0;
1197 uint8_t header_size = 0;
1199 while (counted_size < total_size)
1201 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1202 counted_size += size;
1204 /* check for end of file */
1208 /* we're starting to read a new track, update index,
1209 * so that all data and tables get written in the right place
1211 if (atom_type == ATOM_TRAK)
1216 /* parse subatoms */
1217 if (meta_only && !need_parse_when_meta_only(atom_type))
1219 mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1220 } else if (atom_type < SUBATOMIC)
1222 parse_sub_atoms(f, size-header_size,meta_only);
1224 mp4ff_atom_read(f, (uint32_t)size, atom_type);
1231 /* parse root atoms */
1232 int32_t parse_atoms(mp4ff_t *f,int meta_only)
1235 uint8_t atom_type = 0;
1236 uint8_t header_size = 0;
1239 f->stream->read_error = 0;
1241 while ((size = mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0)
1243 f->file_size += size;
1244 f->last_atom = atom_type;
1246 if (atom_type == ATOM_MDAT && f->moov_read)
1248 /* moov atom is before mdat, we can stop reading when mdat is encountered */
1249 /* file position will stay at beginning of mdat data */
1253 if (atom_type == ATOM_MOOV && size > header_size)
1256 f->moov_offset = mp4ff_position(f)-header_size;
1257 f->moov_size = size;
1260 /* parse subatoms */
1261 if (meta_only && !need_parse_when_meta_only(atom_type))
1263 mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1264 } else if (atom_type < SUBATOMIC)
1266 parse_sub_atoms(f, size-header_size,meta_only);
1268 /* skip this atom */
1269 mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1276 int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
1277 unsigned char** ppBuf, unsigned int* pBufSize)
1279 if (track >= f->total_tracks)
1286 if (f->track[track]->decoderConfig == NULL || f->track[track]->decoderConfigLen == 0)
1291 *ppBuf = malloc(f->track[track]->decoderConfigLen);
1297 memcpy(*ppBuf, f->track[track]->decoderConfig, f->track[track]->decoderConfigLen);
1298 *pBufSize = f->track[track]->decoderConfigLen;
1302 mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f)
1304 mp4ff_t *ff = malloc(sizeof(mp4ff_t));
1306 memset(ff, 0, sizeof(mp4ff_t));
1321 int32_t mp4ff_tag_delete(mp4ff_metadata_t *tags)
1325 for (i = 0; i < tags->count; i++)
1327 if (tags->tags[i].item) free(tags->tags[i].item);
1328 if (tags->tags[i].value) free(tags->tags[i].value);
1331 if (tags->tags) free(tags->tags);
1338 void mp4ff_close(mp4ff_t *ff)
1342 for (i = 0; i < ff->total_tracks; i++)
1346 if (ff->track[i]->stsz_table)
1347 free(ff->track[i]->stsz_table);
1348 if (ff->track[i]->stts_sample_count)
1349 free(ff->track[i]->stts_sample_count);
1350 if (ff->track[i]->stts_sample_delta)
1351 free(ff->track[i]->stts_sample_delta);
1352 if (ff->track[i]->stsc_first_chunk)
1353 free(ff->track[i]->stsc_first_chunk);
1354 if (ff->track[i]->stsc_samples_per_chunk)
1355 free(ff->track[i]->stsc_samples_per_chunk);
1356 if (ff->track[i]->stsc_sample_desc_index)
1357 free(ff->track[i]->stsc_sample_desc_index);
1358 if (ff->track[i]->stco_chunk_offset)
1359 free(ff->track[i]->stco_chunk_offset);
1360 if (ff->track[i]->decoderConfig)
1361 free(ff->track[i]->decoderConfig);
1362 if (ff->track[i]->ctts_sample_count)
1363 free(ff->track[i]->ctts_sample_count);
1364 if (ff->track[i]->ctts_sample_offset)
1365 free(ff->track[i]->ctts_sample_offset);
1367 if (ff->track[i]->p_drms)
1368 drms_free(ff->track[i]->p_drms);
1375 mp4ff_tag_delete(&(ff->tags));
1381 static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample,
1382 int32_t *chunk_sample, int32_t *chunk)
1384 int32_t total_entries = 0;
1385 int32_t chunk2entry;
1386 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1388 if (f->track[track] == NULL)
1393 total_entries = f->track[track]->stsc_entry_count;
1401 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1402 *chunk = chunk2 - chunk1;
1403 range_samples = *chunk * chunk1samples;
1405 if (sample < total + range_samples) break;
1407 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1410 if(chunk2entry < total_entries)
1413 total += range_samples;
1415 } while (chunk2entry < total_entries);
1418 *chunk = (sample - total) / chunk1samples + chunk1;
1422 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1428 static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk)
1430 const mp4ff_track_t * p_track = f->track[track];
1432 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count))
1434 return p_track->stco_chunk_offset[p_track->stco_entry_count - 1];
1435 } else if (p_track->stco_entry_count) {
1436 return p_track->stco_chunk_offset[chunk - 1];
1444 static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track,
1445 const int32_t chunk_sample, const int32_t sample)
1448 const mp4ff_track_t * p_track = f->track[track];
1450 if (p_track->stsz_sample_size)
1452 return (sample - chunk_sample) * p_track->stsz_sample_size;
1456 if (sample>=p_track->stsz_sample_count) return 0;//error
1458 for(i = chunk_sample, total = 0; i < sample; i++)
1460 total += p_track->stsz_table[i];
1466 static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
1468 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1470 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1472 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1473 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f, track, chunk_sample, sample);
1475 return chunk_offset2;
1478 int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample)
1482 offset = mp4ff_sample_to_offset(f, track, sample);
1483 mp4ff_set_position(f, offset);
1488 int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
1491 const mp4ff_track_t * p_track = f->track[track];
1493 if (p_track->stsz_sample_size)
1495 bytes = p_track->stsz_sample_size;
1497 bytes = p_track->stsz_table[sample];
1503 int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample)
1505 int32_t temp = mp4ff_audio_frame_size(f, track, sample);
1506 if (temp<0) temp = 0;
1510 uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track)
1512 return f->track[track]->sampleRate;
1515 uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track)
1517 return f->track[track]->channelCount;
1520 int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
1525 for (i = 0; i < f->track[track]->stts_entry_count; i++)
1527 total += f->track[track]->stts_sample_count[i];
1532 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t *f)
1534 mp4ff_t *ff = malloc(sizeof(mp4ff_t));
1536 memset(ff, 0, sizeof(mp4ff_t));
1551 int32_t mp4ff_meta_get_num_items(const mp4ff_t *f)
1553 return f->tags.count;
1556 int32_t mp4ff_meta_get_by_index(const mp4ff_t *f, uint32_t index,
1557 char **item, char **value)
1559 if (index >= f->tags.count)
1565 *item = strdup(f->tags.tags[index].item);
1566 *value = strdup(f->tags.tags[index].value);
1571 static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
1573 uint32_t remaining = size;
1574 uint64_t atom_offset = base;
1580 mp4ff_set_position(f,atom_offset);
1582 if (remaining < 8) break;
1583 atom_size = mp4ff_read_int32(f);
1584 if (atom_size > remaining || atom_size < 8) break;
1585 mp4ff_read_data(f,atom_name,4);
1587 if (!memcmp(atom_name,name,4))
1589 mp4ff_set_position(f,atom_offset);
1593 remaining -= atom_size;
1594 atom_offset += atom_size;
1598 static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
1600 uint64_t first_base = (uint64_t)(-1);
1601 while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
1603 uint64_t mybase = mp4ff_position(f);
1604 uint32_t mysize = mp4ff_read_int32(f);
1606 if (first_base == (uint64_t)(-1)) first_base = mybase;
1608 if (mysize < 8 + extraheaders) break;
1610 if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
1612 mp4ff_set_position(f,mybase);
1616 if (size<=mysize) {size=0;break;}
1620 if (first_base != (uint64_t)(-1))//wanted atom inside not found
1622 mp4ff_set_position(f,first_base);
1636 #define stricmp strcasecmp
1638 membuffer * membuffer_create()
1640 const unsigned initial_size = 256;
1642 membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
1643 buf->data = malloc(initial_size);
1645 buf->allocated = initial_size;
1646 buf->error = buf->data == 0 ? 1 : 0;
1651 unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
1653 unsigned dest_size = buf->written + bytes;
1655 if (buf->error) return 0;
1656 if (dest_size > buf->allocated)
1660 buf->allocated <<= 1;
1661 } while(dest_size > buf->allocated);
1664 void * newptr = realloc(buf->data,buf->allocated);
1676 if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
1677 buf->written += bytes;
1680 #define membuffer_write_data membuffer_write
1682 unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
1684 return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
1687 unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
1689 uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
1690 return membuffer_write_data(buf,temp,2);
1693 unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
1695 uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
1696 return membuffer_write_data(buf,temp,4);
1699 static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
1701 membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
1702 membuffer_write_atom_name(buf,name);
1703 membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
1704 membuffer_write_atom_name(buf,"data");
1705 membuffer_write_int32(buf,0);//flags
1706 membuffer_write_int32(buf,0);//reserved
1707 membuffer_write_int16(buf,0);
1708 membuffer_write_int16(buf,(uint16_t)index);//track number
1709 membuffer_write_int16(buf,(uint16_t)total);//total tracks
1710 membuffer_write_int16(buf,0);
1713 static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
1715 membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
1716 membuffer_write_atom_name(buf,name);
1717 membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
1718 membuffer_write_atom_name(buf,"data");
1719 membuffer_write_int32(buf,0);//flags
1720 membuffer_write_int32(buf,0);//reserved
1721 membuffer_write_int16(buf,value);//value
1724 static uint32_t myatoi(const char * param)
1726 return param ? atoi(param) : 0;
1729 uint32_t mp4ff_meta_genre_to_index(const char * genrestr)
1732 for(n=0;n<sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]);n++)
1734 if (!stricmp(genrestr,ID3v1GenreList[n])) return n+1;
1745 static stdmeta_entry stdmetas[] =
1747 {"\xA9" "nam","title"},
1748 {"\xA9" "ART","artist"},
1749 {"\xA9" "wrt","writer"},
1750 {"\xA9" "alb","album"},
1751 {"\xA9" "day","date"},
1752 {"\xA9" "too","tool"},
1753 {"\xA9" "cmt","comment"},
1754 // {"\xA9" "gen","genre"},
1755 {"cpil","compilation"},
1756 // {"trkn","track"},
1758 // {"gnre","genre"},
1761 {"aART","album_artist"},
1765 static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
1768 for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
1770 if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
1775 static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
1780 /* special check for compilation flag */
1781 if ( strcmp(name, "cpil") == 0)
1786 membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
1787 membuffer_write_atom_name(buf,name);
1788 membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
1789 membuffer_write_atom_name(buf,"data");
1790 membuffer_write_int32(buf,flags);//flags
1791 membuffer_write_int32(buf,0);//reserved
1792 membuffer_write_data(buf,value,strlen(value));
1795 static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
1797 membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
1798 membuffer_write_atom_name(buf,"----");
1799 membuffer_write_int32(buf,0x1C);//weirdo itunes atom
1800 membuffer_write_atom_name(buf,"mean");
1801 membuffer_write_int32(buf,0);
1802 membuffer_write_data(buf,"com.apple.iTunes",16);
1803 membuffer_write_int32(buf,12 + strlen(name));
1804 membuffer_write_atom_name(buf,"name");
1805 membuffer_write_int32(buf,0);
1806 membuffer_write_data(buf,name,strlen(name));
1807 membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
1808 membuffer_write_atom_name(buf,"data");
1809 membuffer_write_int32(buf,1);//flags
1810 membuffer_write_int32(buf,0);//reserved
1811 membuffer_write_data(buf,value,strlen(value));
1814 unsigned membuffer_error(const membuffer * buf)
1819 void membuffer_free(membuffer * buf)
1821 if (buf->data) free(buf->data);
1825 unsigned membuffer_get_size(const membuffer * buf)
1827 return buf->written;
1830 void * membuffer_detach(membuffer * buf)
1834 if (buf->error) return 0;
1836 ret = realloc(buf->data,buf->written);
1838 if (ret == 0) free(buf->data);
1846 static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
1848 membuffer * buf = membuffer_create();
1850 char * mask = (char*)malloc(data->count);
1851 memset(mask,0,data->count);
1854 const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
1855 const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
1856 const char * genre_ptr = 0, * tempo_ptr = 0;
1857 for(metaptr = 0; metaptr < data->count; metaptr++)
1859 mp4ff_tag_t * tag = &data->tags[metaptr];
1860 if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
1862 if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
1865 else if (!stricmp(tag->item,"totaltracks"))
1867 if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
1870 else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
1872 if (discnumber_ptr==0) discnumber_ptr = tag->value;
1875 else if (!stricmp(tag->item,"totaldiscs"))
1877 if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
1880 else if (!stricmp(tag->item,"genre"))
1882 if (genre_ptr==0) genre_ptr = tag->value;
1885 else if (!stricmp(tag->item,"tempo"))
1887 if (tempo_ptr==0) tempo_ptr = tag->value;
1893 if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
1894 if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
1895 if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
1899 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1901 membuffer_write_std_tag(buf,"©gen",genre_ptr);
1903 membuffer_write_int16_tag(buf,"gnre",(uint16_t)index);
1907 for(metaptr = 0; metaptr < data->count; metaptr++)
1911 mp4ff_tag_t * tag = &data->tags[metaptr];
1912 const char * std_meta_atom = find_standard_meta(tag->item);
1915 membuffer_write_std_tag(buf,std_meta_atom,tag->value);
1919 membuffer_write_custom_tag(buf,tag->item,tag->value);
1926 if (membuffer_error(buf))
1928 membuffer_free(buf);
1932 *out_size = membuffer_get_size(buf);
1933 *out_buffer = membuffer_detach(buf);
1934 membuffer_free(buf);
1939 void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
1941 membuffer_write_int32(buf,size + 8);
1942 membuffer_write_atom_name(buf,name);
1943 membuffer_write_data(buf,data,size);
1946 void * membuffer_get_ptr(const membuffer * buf)
1951 void membuffer_set_error(membuffer * buf)
1956 unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
1961 oldsize = membuffer_get_size(buf);
1962 if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
1964 bufptr = membuffer_get_ptr(buf);
1965 if (bufptr==0) return 0;
1967 if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
1969 membuffer_set_error(buf);
1976 static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
1982 if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
1984 buf = membuffer_create();
1986 membuffer_write_int32(buf,0);
1987 membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
1990 *out_size = membuffer_get_size(buf);
1991 *out_buffer = membuffer_detach(buf);
1992 membuffer_free(buf);
1996 static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
2002 if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
2004 buf = membuffer_create();
2006 membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
2010 *out_size = membuffer_get_size(buf);
2011 *out_buffer = membuffer_detach(buf);
2012 membuffer_free(buf);
2016 static uint32_t fix_byte_order_32(uint32_t src)
2019 uint32_t a, b, c, d;
2022 memcpy(data,&src,sizeof(src));
2023 a = (uint8_t)data[0];
2024 b = (uint8_t)data[1];
2025 c = (uint8_t)data[2];
2026 d = (uint8_t)data[3];
2028 result = (a<<24) | (b<<16) | (c<<8) | d;
2029 return (uint32_t)result;
2032 static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
2034 uint64_t total_base = f->moov_offset + 8;
2035 uint32_t total_size = (uint32_t)(f->moov_size - 8);
2037 uint64_t udta_offset,meta_offset,ilst_offset;
2038 uint32_t udta_size, meta_size, ilst_size;
2040 uint32_t new_ilst_size;
2041 void * new_ilst_buffer;
2047 if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
2050 void * new_udta_buffer;
2051 uint32_t new_udta_size;
2052 if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
2054 buf = membuffer_create();
2055 mp4ff_set_position(f,total_base);
2056 membuffer_transfer_from_file(buf,f,total_size);
2058 membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
2060 free(new_udta_buffer);
2062 *out_size = membuffer_get_size(buf);
2063 *out_buffer = membuffer_detach(buf);
2064 membuffer_free(buf);
2069 udta_offset = mp4ff_position(f);
2070 udta_size = mp4ff_read_int32(f);
2071 if (!find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst"))
2074 void * new_meta_buffer;
2075 uint32_t new_meta_size;
2076 if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
2078 buf = membuffer_create();
2079 mp4ff_set_position(f,total_base);
2080 membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
2082 membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
2083 membuffer_write_atom_name(buf,"udta");
2084 membuffer_transfer_from_file(buf,f,udta_size);
2086 membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
2087 free(new_meta_buffer);
2089 *out_size = membuffer_get_size(buf);
2090 *out_buffer = membuffer_detach(buf);
2091 membuffer_free(buf);
2094 meta_offset = mp4ff_position(f);
2095 meta_size = mp4ff_read_int32(f);
2096 if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
2097 ilst_offset = mp4ff_position(f);
2098 ilst_size = mp4ff_read_int32(f);
2100 if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
2102 size_delta = new_ilst_size - (ilst_size - 8);
2104 *out_size = total_size + size_delta;
2105 *out_buffer = malloc(*out_size);
2106 if (*out_buffer == 0)
2108 free(new_ilst_buffer);
2112 p_out = (uint8_t*)*out_buffer;
2114 mp4ff_set_position(f,total_base);
2115 mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
2116 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2117 mp4ff_read_data(f,p_out,4); p_out += 4;
2118 mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
2119 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2120 mp4ff_read_data(f,p_out,4); p_out += 4;
2121 mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
2122 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2123 mp4ff_read_data(f,p_out,4); p_out += 4;
2125 memcpy(p_out,new_ilst_buffer,new_ilst_size);
2126 p_out += new_ilst_size;
2128 mp4ff_set_position(f,ilst_offset + ilst_size);
2129 mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
2131 free(new_ilst_buffer);
2136 int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size)
2140 result = f->stream->write(f->stream->user_data, data, size);
2142 f->current_position += size;
2147 int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data)
2150 uint32_t a, b, c, d;
2153 *(uint32_t*)temp = data;
2154 a = (uint8_t)temp[0];
2155 b = (uint8_t)temp[1];
2156 c = (uint8_t)temp[2];
2157 d = (uint8_t)temp[3];
2159 result = (a<<24) | (b<<16) | (c<<8) | d;
2161 return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result));
2164 int32_t mp4ff_truncate(mp4ff_t * f)
2166 return f->stream->truncate(f->stream->user_data);
2169 int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
2171 void * new_moov_data;
2172 uint32_t new_moov_size;
2174 mp4ff_t *ff = malloc(sizeof(mp4ff_t));
2176 memset(ff, 0, sizeof(mp4ff_t));
2178 mp4ff_set_position(ff,0);
2183 if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
2189 /* copy moov atom to end of the file */
2190 if (ff->last_atom != ATOM_MOOV)
2192 char *free_data = "free";
2194 /* rename old moov to free */
2195 mp4ff_set_position(ff, ff->moov_offset + 4);
2196 mp4ff_write_data(ff, free_data, 4);
2198 mp4ff_set_position(ff, ff->file_size);
2199 mp4ff_write_int32(ff,new_moov_size + 8);
2200 mp4ff_write_data(ff,"moov",4);
2201 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2205 mp4ff_set_position(ff, ff->moov_offset);
2206 mp4ff_write_int32(ff,new_moov_size + 8);
2207 mp4ff_write_data(ff,"moov",4);
2208 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2217 /* find a metadata item by name */
2218 /* returns 0 if item found, 1 if no such item */
2219 static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value)
2223 for (i = 0; i < f->tags.count; i++)
2225 if (!stricmp(f->tags.tags[i].item, item))
2227 *value = strdup(f->tags.tags[i].value);
2238 int32_t mp4ff_meta_get_artist(const mp4ff_t *f, char **value)
2240 return mp4ff_meta_find_by_name(f, "artist", value);
2243 int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value)
2245 return mp4ff_meta_find_by_name(f, "title", value);
2249 int32_t mp4ff_meta_get_date(const mp4ff_t *f, char **value)
2251 return mp4ff_meta_find_by_name(f, "date", value);
2254 int32_t mp4ff_meta_get_album(const mp4ff_t *f, char **value)
2256 return mp4ff_meta_find_by_name(f, "album", value);
2259 int32_t mp4ff_meta_get_comment(const mp4ff_t *f, char **value)
2261 return mp4ff_meta_find_by_name(f, "comment", value);