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)
440 if (f->total_tracks == 0)
442 t = f->track[f->total_tracks - 1];
443 mp4ff_read_char(f); /* version */
444 mp4ff_read_int24(f); /* flags */
445 t->stsz_sample_size = mp4ff_read_int32(f);
446 t->stsz_sample_count = mp4ff_read_int32(f);
447 if (t->stsz_sample_size != 0)
449 t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
450 for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
451 t->stsz_table[i] = mp4ff_read_int32(f);
455 static int32_t mp4ff_read_stts(mp4ff_t * f)
461 if (f->total_tracks == 0)
463 t = f->track[f->total_tracks - 1];
464 if (t->stts_entry_count)
466 mp4ff_read_char(f); /* version */
467 mp4ff_read_int24(f); /* flags */
468 t->stts_entry_count = mp4ff_read_int32(f);
470 t->stts_sample_count = para_malloc(t->stts_entry_count
472 t->stts_sample_delta = para_malloc(t->stts_entry_count
475 for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
476 t->stts_sample_count[i] = mp4ff_read_int32(f);
477 t->stts_sample_delta[i] = mp4ff_read_int32(f);
482 static int32_t mp4ff_read_ctts(mp4ff_t * f)
487 if (f->total_tracks == 0)
489 t = f->track[f->total_tracks - 1];
490 if (t->ctts_entry_count)
493 mp4ff_read_char(f); /* version */
494 mp4ff_read_int24(f); /* flags */
495 t->ctts_entry_count = mp4ff_read_int32(f);
497 t->ctts_sample_count = para_malloc(t->ctts_entry_count
499 t->ctts_sample_offset = para_malloc(t->ctts_entry_count
503 for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
504 t->ctts_sample_count[i] = mp4ff_read_int32(f);
505 t->ctts_sample_offset[i] = mp4ff_read_int32(f);
510 static int32_t mp4ff_read_stsc(mp4ff_t * f)
515 if (f->total_tracks == 0)
517 t = f->track[f->total_tracks - 1];
519 mp4ff_read_char(f); /* version */
520 mp4ff_read_int24(f); /* flags */
521 t->stsc_entry_count = mp4ff_read_int32(f);
522 t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
523 t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
525 t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
529 for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
530 t->stsc_first_chunk[i] = mp4ff_read_int32(f);
531 t->stsc_samples_per_chunk[i] = mp4ff_read_int32(f);
532 t->stsc_sample_desc_index[i] = mp4ff_read_int32(f);
537 static int32_t mp4ff_read_stco(mp4ff_t * f)
542 if (f->total_tracks == 0)
544 t = f->track[f->total_tracks - 1];
546 mp4ff_read_char(f); /* version */
547 mp4ff_read_int24(f); /* flags */
548 t->stco_entry_count = mp4ff_read_int32(f);
549 t->stco_chunk_offset = para_malloc(t->stco_entry_count
552 for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
553 t->stco_chunk_offset[i] = mp4ff_read_int32(f);
557 static uint16_t mp4ff_read_int16(mp4ff_t * f)
563 mp4ff_read_data(f, data, 2);
564 a = (uint8_t) data[0];
565 b = (uint8_t) data[1];
567 result = (a << 8) | b;
568 return (uint16_t) result;
571 static uint32_t mp4ff_read_mp4_descr_length(mp4ff_t * f)
574 uint8_t numBytes = 0;
578 b = mp4ff_read_char(f);
580 length = (length << 7) | (b & 0x7F);
581 } while ((b & 0x80) && numBytes < 4);
585 static int32_t mp4ff_read_esds(mp4ff_t * f)
591 if (f->total_tracks == 0)
593 t = f->track[f->total_tracks - 1];
594 mp4ff_read_char(f); /* version */
595 mp4ff_read_int24(f); /* flags */
596 /* get and verify ES_DescrTag */
597 tag = mp4ff_read_char(f);
600 if (mp4ff_read_mp4_descr_length(f) < 5 + 15) {
610 /* get and verify DecoderConfigDescrTab */
611 if (mp4ff_read_char(f) != 0x04) {
616 temp = mp4ff_read_mp4_descr_length(f);
620 t->audioType = mp4ff_read_char(f);
621 mp4ff_read_int32(f); //0x15000414 ????
622 t->maxBitrate = mp4ff_read_int32(f);
623 t->avgBitrate = mp4ff_read_int32(f);
625 /* get and verify DecSpecificInfoTag */
626 if (mp4ff_read_char(f) != 0x05) {
631 t->decoderConfigLen = mp4ff_read_mp4_descr_length(f);
632 free(t->decoderConfig);
633 t->decoderConfig = para_malloc(t->decoderConfigLen);
634 mp4ff_read_data(f, t->decoderConfig, t->decoderConfigLen);
635 /* will skip the remainder of the atom */
639 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
642 uint8_t atom_type = 0;
643 uint8_t header_size = 0;
646 if (f->total_tracks == 0)
648 t = f->track[f->total_tracks - 1];
650 for (i = 0; i < 6; i++) {
651 mp4ff_read_char(f); /* reserved */
653 /* data_reference_index */ mp4ff_read_int16(f);
655 mp4ff_read_int32(f); /* reserved */
656 mp4ff_read_int32(f); /* reserved */
658 t->channelCount = mp4ff_read_int16(f);
659 t->sampleSize = mp4ff_read_int16(f);
664 t->sampleRate = mp4ff_read_int16(f);
668 mp4ff_atom_read_header(f, &atom_type, &header_size);
669 if (atom_type == ATOM_ESDS) {
676 static int32_t mp4ff_read_stsd(mp4ff_t * f)
679 uint8_t header_size = 0;
683 if (f->total_tracks == 0)
685 t = f->track[f->total_tracks - 1];
687 mp4ff_read_char(f); /* version */
688 mp4ff_read_int24(f); /* flags */
690 t->stsd_entry_count = mp4ff_read_int32(f);
693 for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
694 uint64_t skip = mp4ff_position(f);
696 uint8_t atom_type = 0;
697 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
700 if (atom_type == ATOM_MP4A) {
701 t->type = TRACK_AUDIO;
703 } else if (atom_type == ATOM_MP4V) {
704 t->type = TRACK_VIDEO;
705 } else if (atom_type == ATOM_MP4S) {
706 t->type = TRACK_SYSTEM;
708 t->type = TRACK_UNKNOWN;
710 mp4ff_set_position(f, skip);
716 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
720 mp4ff_read_char(f); /* version */
721 mp4ff_read_int24(f); /* flags */
722 /* creation_time */ mp4ff_read_int32(f);
723 /* modification_time */ mp4ff_read_int32(f);
724 f->time_scale = mp4ff_read_int32(f);
725 f->duration = mp4ff_read_int32(f);
726 /* preferred_rate */ mp4ff_read_int32(f);
727 /*mp4ff_read_fixed32(f); */
728 /* preferred_volume */ mp4ff_read_int16(f);
729 /*mp4ff_read_fixed16(f); */
730 for (i = 0; i < 10; i++) {
731 /* reserved */ mp4ff_read_char(f);
733 for (i = 0; i < 9; i++) {
734 mp4ff_read_int32(f); /* matrix */
736 /* preview_time */ mp4ff_read_int32(f);
737 /* preview_duration */ mp4ff_read_int32(f);
738 /* poster_time */ mp4ff_read_int32(f);
739 /* selection_time */ mp4ff_read_int32(f);
740 /* selection_duration */ mp4ff_read_int32(f);
741 /* current_time */ mp4ff_read_int32(f);
742 /* next_track_id */ mp4ff_read_int32(f);
747 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
748 const char *value, int32_t len)
750 void *backup = (void *) tags->tags;
752 if (!item || (item && !*item) || !value)
755 tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
756 (tags->count + 1) * sizeof (mp4ff_tag_t));
761 tags->tags[tags->count].item = para_strdup(item);
762 tags->tags[tags->count].len = len;
764 tags->tags[tags->count].value = para_malloc(len + 1);
765 memcpy(tags->tags[tags->count].value, value, len);
766 tags->tags[tags->count].value[len] = 0;
768 tags->tags[tags->count].value = para_strdup(value);
775 static const char *ID3v1GenreList[] = {
776 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
777 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
778 "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
779 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
780 "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
781 "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
782 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
783 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
784 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
785 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
786 "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
787 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
788 "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
789 "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
790 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
791 "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
792 "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
793 "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
794 "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
795 "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
796 "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
797 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
798 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
799 "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
800 "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
801 "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
802 "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
803 "Anime", "JPop", "SynthPop",
806 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
808 if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
809 return ID3v1GenreList[idx - 1];
815 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
817 char *str = para_malloc(length + 1);
818 if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
826 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
828 static char *tag_names[] = {
829 "unknown", "title", "artist", "writer", "album",
830 "date", "tool", "comment", "genre", "track",
831 "disc", "compilation", "genre", "tempo", "cover",
832 "album_artist", "contentgroup", "lyrics", "description",
833 "network", "show", "episodename",
834 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
835 "sortwriter", "sortshow",
836 "season", "episode", "podcast"
871 case ATOM_COMPILATION:
883 case ATOM_ALBUM_ARTIST:
886 case ATOM_CONTENTGROUP:
892 case ATOM_DESCRIPTION:
901 case ATOM_EPISODENAME:
910 case ATOM_SORTARTIST:
913 case ATOM_SORTALBUMARTIST:
916 case ATOM_SORTWRITER:
936 *name = para_strdup(tag_names[tag_idx]);
940 static uint32_t min_body_size(const uint8_t atom_type)
947 return sizeof (char) /* version */
948 + sizeof(uint8_t) * 3 /* flags */
949 + sizeof(uint32_t) /* reserved */
950 + sizeof(uint16_t) /* leading uint16_t */
951 + sizeof(uint16_t) /* track */
952 + sizeof(uint16_t); /* totaltracks */
954 return sizeof (char) /* version */
955 + sizeof(uint8_t) * 3 /* flags */
956 + sizeof(uint32_t) /* reserved */
957 + sizeof(uint16_t) /* disc */
958 + sizeof(uint16_t); /* totaldiscs */
959 default: assert(false);
963 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent,
967 uint8_t header_size = 0;
968 uint64_t subsize, sumsize;
977 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
978 mp4ff_set_position(f, destpos), sumsize += subsize
980 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
981 destpos = mp4ff_position(f) + subsize - header_size;
984 if (atom_type == ATOM_NAME) {
985 mp4ff_read_char(f); /* version */
986 mp4ff_read_int24(f); /* flags */
988 name = mp4ff_read_string(f, subsize - (header_size + 4));
991 if (atom_type != ATOM_DATA)
993 mp4ff_read_char(f); /* version */
994 mp4ff_read_int24(f); /* flags */
995 mp4ff_read_int32(f); /* reserved */
997 /* some need special attention */
998 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1000 if (subsize - header_size < min_body_size(parent))
1002 val = mp4ff_read_int16(f);
1003 if (parent == ATOM_TEMPO) {
1005 sprintf(temp, "%.5u BPM", val);
1006 mp4ff_tag_add_field(&(f-> tags), "tempo",
1009 const char *tmp = mp4ff_meta_index_to_genre(val);
1011 mp4ff_tag_add_field (&(f->tags),
1015 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1016 uint16_t index, total;
1018 if (subsize - header_size < min_body_size(parent))
1020 mp4ff_read_int16(f);
1021 index = mp4ff_read_int16(f);
1022 total = mp4ff_read_int16(f);
1023 if (parent == ATOM_TRACK)
1024 mp4ff_read_int16(f);
1025 sprintf(temp, "%d", index);
1026 mp4ff_tag_add_field(&(f->tags), parent == ATOM_TRACK?
1027 "track" : "disc", temp, -1);
1029 sprintf(temp, "%d", total);
1030 mp4ff_tag_add_field(& (f-> tags),
1031 parent == ATOM_TRACK?
1032 "totaltracks" : "totaldiscs", temp, -1);
1037 data = mp4ff_read_string(f, subsize - (header_size + 8));
1038 len = subsize - (header_size + 8);
1044 mp4ff_set_metadata_name(parent , &name);
1046 mp4ff_tag_add_field(&(f->tags), name, data, len);
1055 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1061 if (f->total_tracks == 0)
1063 t = f->track[f->total_tracks - 1];
1065 version = mp4ff_read_int32(f);
1067 mp4ff_read_int64(f); //creation-time
1068 mp4ff_read_int64(f); //modification-time
1069 t->timeScale = mp4ff_read_int32(f); //timescale
1070 t->duration = mp4ff_read_int64(f); //duration
1071 } else { //version == 0
1074 mp4ff_read_int32(f); //creation-time
1075 mp4ff_read_int32(f); //modification-time
1076 t->timeScale = mp4ff_read_int32(f); //timescale
1077 temp = mp4ff_read_int32(f);
1078 t->duration = (temp == (uint32_t) (-1))?
1079 (uint64_t) (-1) : (uint64_t) (temp);
1081 mp4ff_read_int16(f);
1082 mp4ff_read_int16(f);
1086 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1088 uint64_t subsize, sumsize = 0;
1090 uint8_t header_size = 0;
1092 while (sumsize < size) {
1093 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1096 mp4ff_parse_tag(f, atom_type,
1097 (uint32_t) (subsize - header_size));
1104 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1106 uint64_t subsize, sumsize = 0;
1108 uint8_t header_size = 0;
1110 mp4ff_read_char(f); /* version */
1111 mp4ff_read_int24(f); /* flags */
1113 while (sumsize < (size - (header_size + 4))) {
1114 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1115 if (subsize <= header_size + 4)
1117 if (atom_type == ATOM_ILST) {
1118 mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1120 mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1128 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1129 const uint8_t atom_type)
1131 uint64_t dest_position = mp4ff_position(f) + size - 8;
1132 if (atom_type == ATOM_STSZ) {
1133 /* sample size box */
1135 } else if (atom_type == ATOM_STTS) {
1136 /* time to sample box */
1138 } else if (atom_type == ATOM_CTTS) {
1139 /* composition offset box */
1141 } else if (atom_type == ATOM_STSC) {
1142 /* sample to chunk box */
1144 } else if (atom_type == ATOM_STCO) {
1145 /* chunk offset box */
1147 } else if (atom_type == ATOM_STSD) {
1148 /* sample description box */
1150 } else if (atom_type == ATOM_MVHD) {
1151 /* movie header box */
1153 } else if (atom_type == ATOM_MDHD) {
1156 } else if (atom_type == ATOM_META) {
1157 /* iTunes Metadata box */
1158 mp4ff_read_meta(f, size);
1161 mp4ff_set_position(f, dest_position);
1165 /* parse atoms that are sub atoms of other atoms */
1166 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1169 uint8_t atom_type = 0;
1170 uint64_t counted_size = 0;
1171 uint8_t header_size = 0;
1173 while (counted_size < total_size) {
1174 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1175 counted_size += size;
1177 /* check for end of file */
1181 /* we're starting to read a new track, update index,
1182 * so that all data and tables get written in the right place
1184 if (atom_type == ATOM_TRAK) {
1188 /* parse subatoms */
1189 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1190 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1191 } else if (atom_type < SUBATOMIC) {
1192 parse_sub_atoms(f, size - header_size, meta_only);
1194 mp4ff_atom_read(f, (uint32_t) size, atom_type);
1201 /* parse root atoms */
1202 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1205 uint8_t atom_type = 0;
1206 uint8_t header_size = 0;
1209 f->stream->read_error = 0;
1212 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1213 f->file_size += size;
1214 f->last_atom = atom_type;
1216 if (atom_type == ATOM_MOOV && size > header_size) {
1217 f->moov_offset = mp4ff_position(f) - header_size;
1218 f->moov_size = size;
1221 /* parse subatoms */
1222 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1223 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1224 } else if (atom_type < SUBATOMIC) {
1225 parse_sub_atoms(f, size - header_size, meta_only);
1227 /* skip this atom */
1228 mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1235 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1236 unsigned char **ppBuf, unsigned int *pBufSize)
1238 if (track >= f->total_tracks) {
1244 if (f->track[track]->decoderConfig == NULL
1245 || f->track[track]->decoderConfigLen == 0) {
1249 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1250 memcpy(*ppBuf, f->track[track]->decoderConfig,
1251 f->track[track]->decoderConfigLen);
1252 *pBufSize = f->track[track]->decoderConfigLen;
1256 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1258 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1272 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1276 for (i = 0; i < tags->count; i++) {
1277 free(tags->tags[i].item);
1278 free(tags->tags[i].value);
1287 void mp4ff_close(mp4ff_t * ff)
1291 for (i = 0; i < ff->total_tracks; i++) {
1293 free(ff->track[i]->stsz_table);
1294 free(ff->track[i]->stts_sample_count);
1295 free(ff->track[i]->stts_sample_delta);
1296 free(ff->track[i]->stsc_first_chunk);
1297 free(ff->track[i]->stsc_samples_per_chunk);
1298 free(ff->track[i]->stsc_sample_desc_index);
1299 free(ff->track[i]->stco_chunk_offset);
1300 free(ff->track[i]->decoderConfig);
1301 free(ff->track[i]->ctts_sample_count);
1302 free(ff->track[i]->ctts_sample_offset);
1307 mp4ff_tag_delete(&(ff->tags));
1311 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1312 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1314 int32_t total_entries = 0;
1315 int32_t chunk2entry;
1316 int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1320 if (f->track[track] == NULL) {
1324 total_entries = f->track[track]->stsc_entry_count;
1331 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1332 *chunk = chunk2 - chunk1;
1333 range_samples = *chunk * chunk1samples;
1335 if (sample < total + range_samples)
1338 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1341 if (chunk2entry < total_entries) {
1343 total += range_samples;
1345 } while (chunk2entry < total_entries);
1348 *chunk = (sample - total) / chunk1samples + chunk1;
1352 *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1357 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1358 const int32_t chunk)
1360 const mp4ff_track_t *p_track = f->track[track];
1362 if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1363 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1365 } else if (p_track->stco_entry_count) {
1366 return p_track->stco_chunk_offset[chunk - 1];
1374 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1375 const int32_t chunk_sample, const int32_t sample)
1378 const mp4ff_track_t *p_track = f->track[track];
1380 if (p_track->stsz_sample_size) {
1381 return (sample - chunk_sample) * p_track->stsz_sample_size;
1383 if (sample >= p_track->stsz_sample_count)
1386 for (i = chunk_sample, total = 0; i < sample; i++) {
1387 total += p_track->stsz_table[i];
1393 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1394 const int32_t sample)
1396 int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1398 mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1400 chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1401 chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1402 track, chunk_sample, sample);
1403 return chunk_offset2;
1406 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1407 const int32_t sample)
1409 int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1410 mp4ff_set_position(f, offset);
1413 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1415 const mp4ff_track_t *t = f->track[track];
1417 if (t->stsz_sample_size != 0)
1418 return t->stsz_sample_size;
1419 return t->stsz_table[sample];
1422 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1424 return f->track[track]->sampleRate;
1427 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1429 return f->track[track]->channelCount;
1432 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1437 for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1438 total += f->track[track]->stts_sample_count[i];
1443 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1445 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1459 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1461 return f->tags.count;
1464 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1465 char **item, char **value)
1467 if (index >= f->tags.count) {
1472 *item = para_strdup(f->tags.tags[index].item);
1473 *value = para_strdup(f->tags.tags[index].value);
1478 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1481 uint32_t remaining = size;
1482 uint64_t atom_offset = base;
1487 mp4ff_set_position(f, atom_offset);
1491 atom_size = mp4ff_read_int32(f);
1492 if (atom_size > remaining || atom_size < 8)
1494 mp4ff_read_data(f, atom_name, 4);
1496 if (!memcmp(atom_name, name, 4)) {
1497 mp4ff_set_position(f, atom_offset);
1501 remaining -= atom_size;
1502 atom_offset += atom_size;
1506 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1507 const char *name, uint32_t extraheaders, const char *name_inside)
1509 uint64_t first_base = (uint64_t) (-1);
1510 while (find_atom(f, base, size, name)) //try to find atom <name> with atom <name_inside> in it
1512 uint64_t mybase = mp4ff_position(f);
1513 uint32_t mysize = mp4ff_read_int32(f);
1515 if (first_base == (uint64_t) (-1))
1516 first_base = mybase;
1518 if (mysize < 8 + extraheaders)
1521 if (find_atom (f, mybase + (8 + extraheaders),
1522 mysize - (8 + extraheaders), name_inside)) {
1523 mp4ff_set_position(f, mybase);
1527 if (size <= mysize) {
1534 if (first_base != (uint64_t) (-1)) //wanted atom inside not found
1536 mp4ff_set_position(f, first_base);
1549 #define stricmp strcasecmp
1551 static membuffer *membuffer_create(void)
1553 const unsigned initial_size = 256;
1555 membuffer *buf = para_malloc(sizeof (membuffer));
1556 buf->data = para_malloc(initial_size);
1558 buf->allocated = initial_size;
1559 buf->error = buf->data == 0 ? 1 : 0;
1564 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1566 unsigned dest_size = buf->written + bytes;
1570 if (dest_size > buf->allocated) {
1572 buf->allocated <<= 1;
1573 } while (dest_size > buf->allocated);
1576 void *newptr = realloc(buf->data, buf->allocated);
1588 memcpy((char *) buf->data + buf->written, ptr, bytes);
1589 buf->written += bytes;
1593 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1595 return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1598 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1600 uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1601 return membuffer_write(buf, temp, 2);
1604 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1606 uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1607 (uint8_t) (data >> 8), (uint8_t) data };
1608 return membuffer_write(buf, temp, 4);
1611 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1612 uint32_t index, uint32_t total)
1614 membuffer_write_int32(buf,
1615 8 /*atom header */ + 8 /*data atom header */ +
1616 8 /*flags + reserved */ + 8 /*actual data */ );
1617 membuffer_write_atom_name(buf, name);
1618 membuffer_write_int32(buf,
1619 8 /*data atom header */ +
1620 8 /*flags + reserved */ + 8 /*actual data */ );
1621 membuffer_write_atom_name(buf, "data");
1622 membuffer_write_int32(buf, 0); //flags
1623 membuffer_write_int32(buf, 0); //reserved
1624 membuffer_write_int16(buf, 0);
1625 membuffer_write_int16(buf, (uint16_t) index); //track number
1626 membuffer_write_int16(buf, (uint16_t) total); //total tracks
1627 membuffer_write_int16(buf, 0);
1630 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1633 membuffer_write_int32(buf,
1634 8 /*atom header */ + 8 /*data atom header */ +
1635 8 /*flags + reserved */ + 2 /*actual data */ );
1636 membuffer_write_atom_name(buf, name);
1637 membuffer_write_int32(buf,
1638 8 /*data atom header */ +
1639 8 /*flags + reserved */ + 2 /*actual data */ );
1640 membuffer_write_atom_name(buf, "data");
1641 membuffer_write_int32(buf, 0); //flags
1642 membuffer_write_int32(buf, 0); //reserved
1643 membuffer_write_int16(buf, value); //value
1646 static uint32_t myatoi(const char *param)
1648 return param ? atoi(param) : 0;
1651 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1654 for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1655 if (!stricmp(genrestr, ID3v1GenreList[n]))
1666 static stdmeta_entry stdmetas[] = {
1667 {"\xA9" "nam", "title"},
1668 {"\xA9" "ART", "artist"},
1669 {"\xA9" "wrt", "writer"},
1670 {"\xA9" "alb", "album"},
1671 {"\xA9" "day", "date"},
1672 {"\xA9" "too", "tool"},
1673 {"\xA9" "cmt", "comment"},
1674 {"cpil", "compilation"},
1676 {"aART", "album_artist"},
1679 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1682 for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1683 if (!stricmp(name, stdmetas[n].name))
1684 return stdmetas[n].atom;
1689 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1694 /* special check for compilation flag */
1695 if (strcmp(name, "cpil") == 0) {
1699 membuffer_write_int32(buf,
1700 8 /*atom header */ + 8 /*data atom header */ +
1701 8 /*flags + reserved */ + strlen(value));
1702 membuffer_write_atom_name(buf, name);
1703 membuffer_write_int32(buf,
1704 8 /*data atom header */ +
1705 8 /*flags + reserved */ + strlen(value));
1706 membuffer_write_atom_name(buf, "data");
1707 membuffer_write_int32(buf, flags); //flags
1708 membuffer_write_int32(buf, 0); //reserved
1709 membuffer_write(buf, value, strlen(value));
1712 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1715 membuffer_write_int32(buf,
1716 8 /*atom header */ +
1717 0x1C /*weirdo itunes atom */ +
1718 12 /*name atom header */ + strlen(name) +
1719 16 /*data atom header + flags */ + strlen(value));
1720 membuffer_write_atom_name(buf, "----");
1721 membuffer_write_int32(buf, 0x1C); //weirdo itunes atom
1722 membuffer_write_atom_name(buf, "mean");
1723 membuffer_write_int32(buf, 0);
1724 membuffer_write(buf, "com.apple.iTunes", 16);
1725 membuffer_write_int32(buf, 12 + strlen(name));
1726 membuffer_write_atom_name(buf, "name");
1727 membuffer_write_int32(buf, 0);
1728 membuffer_write(buf, name, strlen(name));
1729 membuffer_write_int32(buf,
1730 8 /*data atom header */ +
1731 8 /*flags + reserved */ + strlen(value));
1732 membuffer_write_atom_name(buf, "data");
1733 membuffer_write_int32(buf, 1); //flags
1734 membuffer_write_int32(buf, 0); //reserved
1735 membuffer_write(buf, value, strlen(value));
1738 static unsigned membuffer_error(const membuffer * buf)
1743 static void membuffer_free(membuffer * buf)
1749 static unsigned membuffer_get_size(const membuffer * buf)
1751 return buf->written;
1754 static void *membuffer_detach(membuffer * buf)
1761 ret = realloc(buf->data, buf->written);
1772 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1773 uint32_t * out_size)
1775 membuffer *buf = membuffer_create();
1777 char *mask = para_calloc(data->count);
1779 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1780 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1781 const char *genre_ptr = 0, *tempo_ptr = 0;
1782 for (metaptr = 0; metaptr < data->count; metaptr++) {
1783 mp4ff_tag_t *tag = &data->tags[metaptr];
1784 if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1785 if (tracknumber_ptr == 0)
1786 tracknumber_ptr = tag->value;
1788 } else if (!stricmp(tag->item, "totaltracks")) {
1789 if (totaltracks_ptr == 0)
1790 totaltracks_ptr = tag->value;
1792 } else if (!stricmp(tag->item, "discnumber")
1793 || !stricmp(tag->item, "disc")) {
1794 if (discnumber_ptr == 0)
1795 discnumber_ptr = tag->value;
1797 } else if (!stricmp(tag->item, "totaldiscs")) {
1798 if (totaldiscs_ptr == 0)
1799 totaldiscs_ptr = tag->value;
1801 } else if (!stricmp(tag->item, "genre")) {
1803 genre_ptr = tag->value;
1805 } else if (!stricmp(tag->item, "tempo")) {
1807 tempo_ptr = tag->value;
1813 if (tracknumber_ptr)
1814 membuffer_write_track_tag(buf, "trkn",
1815 myatoi(tracknumber_ptr),
1816 myatoi(totaltracks_ptr));
1818 membuffer_write_track_tag(buf, "disk",
1819 myatoi(discnumber_ptr),
1820 myatoi(totaldiscs_ptr));
1822 membuffer_write_int16_tag(buf, "tmpo",
1823 (uint16_t) myatoi(tempo_ptr));
1826 uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1828 membuffer_write_std_tag(buf, "©gen",
1831 membuffer_write_int16_tag(buf, "gnre",
1836 for (metaptr = 0; metaptr < data->count; metaptr++) {
1837 if (!mask[metaptr]) {
1838 mp4ff_tag_t *tag = &data->tags[metaptr];
1839 const char *std_meta_atom = find_standard_meta(tag->item);
1840 if (std_meta_atom) {
1841 membuffer_write_std_tag(buf, std_meta_atom,
1844 membuffer_write_custom_tag(buf, tag->item,
1852 if (membuffer_error(buf)) {
1853 membuffer_free(buf);
1857 *out_size = membuffer_get_size(buf);
1858 *out_buffer = membuffer_detach(buf);
1859 membuffer_free(buf);
1864 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1867 membuffer_write_int32(buf, size + 8);
1868 membuffer_write_atom_name(buf, name);
1869 membuffer_write(buf, data, size);
1872 static void *membuffer_get_ptr(const membuffer * buf)
1877 static void membuffer_set_error(membuffer * buf)
1882 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1888 oldsize = membuffer_get_size(buf);
1889 if (membuffer_write(buf, 0, bytes) != bytes)
1892 bufptr = membuffer_get_ptr(buf);
1896 if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1898 membuffer_set_error(buf);
1905 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1906 uint32_t * out_size)
1912 if (!create_ilst(data, &ilst_buffer, &ilst_size))
1915 buf = membuffer_create();
1917 membuffer_write_int32(buf, 0);
1918 membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1921 *out_size = membuffer_get_size(buf);
1922 *out_buffer = membuffer_detach(buf);
1923 membuffer_free(buf);
1927 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1928 uint32_t * out_size)
1934 if (!create_meta(data, &meta_buffer, &meta_size))
1937 buf = membuffer_create();
1939 membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1943 *out_size = membuffer_get_size(buf);
1944 *out_buffer = membuffer_detach(buf);
1945 membuffer_free(buf);
1949 static uint32_t fix_byte_order_32(uint32_t src)
1952 uint32_t a, b, c, d;
1955 memcpy(data, &src, sizeof (src));
1956 a = (uint8_t) data[0];
1957 b = (uint8_t) data[1];
1958 c = (uint8_t) data[2];
1959 d = (uint8_t) data[3];
1961 result = (a << 24) | (b << 16) | (c << 8) | d;
1962 return (uint32_t) result;
1965 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1966 void **out_buffer, uint32_t * out_size)
1968 uint64_t total_base = f->moov_offset + 8;
1969 uint32_t total_size = (uint32_t) (f->moov_size - 8);
1971 uint64_t udta_offset, meta_offset, ilst_offset;
1972 uint32_t udta_size, meta_size, ilst_size;
1974 uint32_t new_ilst_size;
1975 void *new_ilst_buffer;
1980 if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1982 void *new_udta_buffer;
1983 uint32_t new_udta_size;
1984 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1987 buf = membuffer_create();
1988 mp4ff_set_position(f, total_base);
1989 membuffer_transfer_from_file(buf, f, total_size);
1991 membuffer_write_atom(buf, "udta", new_udta_size,
1994 free(new_udta_buffer);
1996 *out_size = membuffer_get_size(buf);
1997 *out_buffer = membuffer_detach(buf);
1998 membuffer_free(buf);
2001 udta_offset = mp4ff_position(f);
2002 udta_size = mp4ff_read_int32(f);
2003 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2005 void *new_meta_buffer;
2006 uint32_t new_meta_size;
2007 if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2010 buf = membuffer_create();
2011 mp4ff_set_position(f, total_base);
2012 membuffer_transfer_from_file(buf, f,
2013 (uint32_t)(udta_offset - total_base));
2015 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2016 membuffer_write_atom_name(buf, "udta");
2017 membuffer_transfer_from_file(buf, f, udta_size);
2019 membuffer_write_atom(buf, "meta", new_meta_size,
2021 free(new_meta_buffer);
2023 *out_size = membuffer_get_size(buf);
2024 *out_buffer = membuffer_detach(buf);
2025 membuffer_free(buf);
2028 meta_offset = mp4ff_position(f);
2029 meta_size = mp4ff_read_int32(f);
2030 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2031 return 0; //shouldn't happen, find_atom_v2 above takes care of it
2032 ilst_offset = mp4ff_position(f);
2033 ilst_size = mp4ff_read_int32(f);
2035 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2038 size_delta = new_ilst_size - (ilst_size - 8);
2040 *out_size = total_size + size_delta;
2041 *out_buffer = para_malloc(*out_size);
2042 p_out = (uint8_t *) * out_buffer;
2044 mp4ff_set_position(f, total_base);
2045 mp4ff_read_data(f, p_out,
2046 (uint32_t) (udta_offset - total_base));
2047 p_out += (uint32_t) (udta_offset - total_base);
2048 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2050 mp4ff_read_data(f, p_out, 4);
2052 mp4ff_read_data(f, p_out,
2053 (uint32_t) (meta_offset - udta_offset - 8));
2054 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2055 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2057 mp4ff_read_data(f, p_out, 4);
2059 mp4ff_read_data(f, p_out,
2060 (uint32_t) (ilst_offset - meta_offset - 8));
2061 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2062 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2064 mp4ff_read_data(f, p_out, 4);
2067 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2068 p_out += new_ilst_size;
2070 mp4ff_set_position(f, ilst_offset + ilst_size);
2071 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2072 - (ilst_offset - total_base) - ilst_size));
2074 free(new_ilst_buffer);
2079 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2083 result = f->stream->write(f->stream->user_data, data, size);
2085 f->current_position += size;
2090 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2093 uint32_t a, b, c, d;
2096 *(uint32_t *) temp = data;
2097 a = (uint8_t) temp[0];
2098 b = (uint8_t) temp[1];
2099 c = (uint8_t) temp[2];
2100 d = (uint8_t) temp[3];
2102 result = (a << 24) | (b << 16) | (c << 8) | d;
2104 return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2107 static int32_t mp4ff_truncate(mp4ff_t * f)
2109 return f->stream->truncate(f->stream->user_data);
2112 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2114 void *new_moov_data;
2115 uint32_t new_moov_size;
2117 mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2119 mp4ff_set_position(ff, 0);
2123 if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2128 /* copy moov atom to end of the file */
2129 if (ff->last_atom != ATOM_MOOV) {
2130 char *free_data = "free";
2132 /* rename old moov to free */
2133 mp4ff_set_position(ff, ff->moov_offset + 4);
2134 mp4ff_write_data(ff, free_data, 4);
2136 mp4ff_set_position(ff, ff->file_size);
2137 mp4ff_write_int32(ff, new_moov_size + 8);
2138 mp4ff_write_data(ff, "moov", 4);
2139 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2141 mp4ff_set_position(ff, ff->moov_offset);
2142 mp4ff_write_int32(ff, new_moov_size + 8);
2143 mp4ff_write_data(ff, "moov", 4);
2144 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2153 /* find a metadata item by name */
2154 /* returns 0 if item found, 1 if no such item */
2155 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2160 for (i = 0; i < f->tags.count; i++) {
2161 if (!stricmp(f->tags.tags[i].item, item)) {
2162 *value = para_strdup(f->tags.tags[i].value);
2173 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2175 return mp4ff_meta_find_by_name(f, "artist", value);
2178 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2180 return mp4ff_meta_find_by_name(f, "title", value);
2183 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2185 return mp4ff_meta_find_by_name(f, "date", value);
2188 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2190 return mp4ff_meta_find_by_name(f, "album", value);
2193 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2195 return mp4ff_meta_find_by_name(f, "comment", value);