]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
mp4: Introduce mp4_is_audio_track().
[paraslash.git] / mp4.c
1 /*
2  * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3  * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
4  *
5  * See file COPYING.
6  */
7
8 #include <regex.h>
9
10 #include "para.h"
11 #include "portable_io.h"
12 #include "string.h"
13 #include "mp4.h"
14
15 struct mp4_track {
16         int32_t type;
17         int32_t channelCount;
18         int32_t sampleSize;
19         uint16_t sampleRate;
20         int32_t audioType;
21
22         /* stsd */
23         int32_t stsd_entry_count;
24
25         /* stsz */
26         int32_t stsz_sample_size;
27         int32_t stsz_sample_count;
28         int32_t *stsz_table;
29
30         /* stts */
31         int32_t stts_entry_count;
32         int32_t *stts_sample_count;
33         int32_t *stts_sample_delta;
34
35         /* stsc */
36         int32_t stsc_entry_count;
37         int32_t *stsc_first_chunk;
38         int32_t *stsc_samples_per_chunk;
39         int32_t *stsc_sample_desc_index;
40
41         /* stsc */
42         int32_t stco_entry_count;
43         int32_t *stco_chunk_offset;
44
45         /* ctts */
46         int32_t ctts_entry_count;
47         int32_t *ctts_sample_count;
48         int32_t *ctts_sample_offset;
49
50         /* esde */
51         uint8_t *decoderConfig;
52         int32_t decoderConfigLen;
53
54         uint32_t maxBitrate;
55         uint32_t avgBitrate;
56
57         uint32_t timeScale;
58         uint64_t duration;
59 };
60
61 #define MAX_TRACKS 1024
62
63 struct mp4 {
64         /* stream to read from */
65         struct mp4_callback *stream;
66         int64_t current_position;
67
68         uint64_t moov_offset;
69         uint64_t moov_size;
70         uint8_t last_atom;
71         uint64_t file_size;
72         uint32_t error;
73
74         /* mvhd */
75         int32_t time_scale;
76         int32_t duration;
77
78         /* incremental track index while reading the file */
79         int32_t total_tracks;
80
81         /* track data */
82         struct mp4_track *track[MAX_TRACKS];
83
84         /* metadata */
85         struct mp4_metadata tags;
86 };
87
88 int32_t mp4_total_tracks(const struct mp4 *f)
89 {
90         return f->total_tracks;
91 }
92
93 static int32_t read_data(struct mp4 *f, void *data, uint32_t size)
94 {
95         int32_t result = 1;
96
97         result = f->stream->read(f->stream->user_data, data, size);
98
99         if (result < size)
100                 f->stream->read_error++;
101
102         f->current_position += size;
103
104         return result;
105 }
106
107 static uint64_t read_int64(struct mp4 *f)
108 {
109         uint8_t data[8];
110
111         read_data(f, data, 8);
112         return read_u64_be(data);
113 }
114
115 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
116 static int32_t atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
117                 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
118 {
119         if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
120                 return 1;
121         else
122                 return 0;
123 }
124
125 enum tracks {
126         TRACK_UNKNOWN = 0,
127         TRACK_AUDIO  = 1,
128         TRACK_VIDEO = 2,
129         TRACK_SYSTEM = 3
130 };
131
132 enum atoms {
133         /* atoms with subatoms */
134         ATOM_MOOV = 1,
135         ATOM_TRAK = 2,
136         ATOM_EDTS = 3,
137         ATOM_MDIA = 4,
138         ATOM_MINF = 5,
139         ATOM_STBL = 6,
140         ATOM_UDTA = 7,
141         ATOM_ILST = 8, /* iTunes Metadata list */
142         ATOM_TITLE = 9,
143         ATOM_ARTIST = 10,
144         ATOM_WRITER = 11,
145         ATOM_ALBUM = 12,
146         ATOM_DATE = 13,
147         ATOM_TOOL = 14,
148         ATOM_COMMENT = 15,
149         ATOM_GENRE1 = 16,
150         ATOM_TRACK = 17,
151         ATOM_DISC = 18,
152         ATOM_COMPILATION = 19,
153         ATOM_GENRE2 = 20,
154         ATOM_TEMPO = 21,
155         ATOM_COVER = 22,
156         ATOM_DRMS = 23,
157         ATOM_SINF = 24,
158         ATOM_SCHI = 25,
159
160         SUBATOMIC = 128,
161
162         /* atoms without subatoms */
163         ATOM_FTYP = 129,
164         ATOM_MDAT = 130,
165         ATOM_MVHD = 131,
166         ATOM_TKHD = 132,
167         ATOM_TREF = 133,
168         ATOM_MDHD = 134,
169         ATOM_VMHD = 135,
170         ATOM_SMHD = 136,
171         ATOM_HMHD = 137,
172         ATOM_STSD = 138,
173         ATOM_STTS = 139,
174         ATOM_STSZ = 140,
175         ATOM_STZ2 = 141,
176         ATOM_STCO = 142,
177         ATOM_STSC = 143,
178         ATOM_MP4A = 144,
179         ATOM_MP4V = 145,
180         ATOM_MP4S = 146,
181         ATOM_ESDS = 147,
182         ATOM_META = 148, /* iTunes Metadata box */
183         ATOM_NAME = 149, /* iTunes Metadata name box */
184         ATOM_DATA = 150, /* iTunes Metadata data box */
185         ATOM_CTTS = 151,
186         ATOM_FRMA = 152,
187         ATOM_IVIV = 153,
188         ATOM_PRIV = 154,
189         ATOM_USER = 155,
190         ATOM_KEY = 156,
191         ATOM_ALBUM_ARTIST = 157,
192         ATOM_CONTENTGROUP = 158,
193         ATOM_LYRICS = 159,
194         ATOM_DESCRIPTION = 160,
195         ATOM_NETWORK = 161,
196         ATOM_SHOW = 162,
197         ATOM_EPISODENAME = 163,
198         ATOM_SORTTITLE = 164,
199         ATOM_SORTALBUM = 165,
200         ATOM_SORTARTIST = 166,
201         ATOM_SORTALBUMARTIST = 167,
202         ATOM_SORTWRITER = 168,
203         ATOM_SORTSHOW = 169,
204         ATOM_SEASON = 170,
205         ATOM_EPISODE = 171,
206         ATOM_PODCAST = 172,
207
208         ATOM_UNKNOWN = 255
209 };
210
211 #define ATOM_FREE ATOM_UNKNOWN
212 #define ATOM_SKIP ATOM_UNKNOWN
213
214 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
215
216 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
217 {
218         if (a == 'm') {
219                 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
220                         return ATOM_MOOV;
221                 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
222                         return ATOM_MINF;
223                 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
224                         return ATOM_MDIA;
225                 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
226                         return ATOM_MDAT;
227                 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
228                         return ATOM_MDHD;
229                 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
230                         return ATOM_MVHD;
231                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
232                         return ATOM_MP4A;
233                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
234                         return ATOM_MP4V;
235                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
236                         return ATOM_MP4S;
237                 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
238                         return ATOM_META;
239         } else if (a == 't') {
240                 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
241                         return ATOM_TRAK;
242                 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
243                         return ATOM_TKHD;
244                 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
245                         return ATOM_TREF;
246                 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
247                         return ATOM_TRACK;
248                 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
249                         return ATOM_TEMPO;
250                 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
251                         return ATOM_NETWORK;
252                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
253                         return ATOM_SHOW;
254                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
255                         return ATOM_EPISODENAME;
256                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
257                         return ATOM_SEASON;
258                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
259                         return ATOM_EPISODE;
260         } else if (a == 's') {
261                 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
262                         return ATOM_STBL;
263                 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
264                         return ATOM_SMHD;
265                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
266                         return ATOM_STSD;
267                 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
268                         return ATOM_STTS;
269                 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
270                         return ATOM_STCO;
271                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
272                         return ATOM_STSC;
273                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
274                         return ATOM_STSZ;
275                 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
276                         return ATOM_STZ2;
277                 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
278                         return ATOM_SKIP;
279                 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
280                         return ATOM_SINF;
281                 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
282                         return ATOM_SCHI;
283                 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
284                         return ATOM_SORTTITLE;
285                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
286                         return ATOM_SORTALBUM;
287                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
288                         return ATOM_SORTARTIST;
289                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
290                         return ATOM_SORTALBUMARTIST;
291                 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
292                         return ATOM_SORTWRITER;
293                 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
294                         return ATOM_SORTSHOW;
295         } else if (a == COPYRIGHT_SYMBOL) {
296                 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
297                         return ATOM_TITLE;
298                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
299                         return ATOM_ARTIST;
300                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
301                         return ATOM_WRITER;
302                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
303                         return ATOM_ALBUM;
304                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
305                         return ATOM_DATE;
306                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
307                         return ATOM_TOOL;
308                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
309                         return ATOM_COMMENT;
310                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
311                         return ATOM_GENRE1;
312                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
313                         return ATOM_CONTENTGROUP;
314                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
315                         return ATOM_LYRICS;
316         }
317
318         if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
319                 return ATOM_EDTS;
320         else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
321                 return ATOM_ESDS;
322         else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
323                 return ATOM_FTYP;
324         else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
325                 return ATOM_FREE;
326         else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
327                 return ATOM_HMHD;
328         else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
329                 return ATOM_VMHD;
330         else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
331                 return ATOM_UDTA;
332         else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
333                 return ATOM_ILST;
334         else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
335                 return ATOM_NAME;
336         else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
337                 return ATOM_DATA;
338         else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
339                 return ATOM_DISC;
340         else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
341                 return ATOM_GENRE2;
342         else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
343                 return ATOM_COVER;
344         else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
345                 return ATOM_COMPILATION;
346         else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
347                 return ATOM_CTTS;
348         else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
349                 return ATOM_DRMS;
350         else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
351                 return ATOM_FRMA;
352         else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
353                 return ATOM_PRIV;
354         else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
355                 return ATOM_IVIV;
356         else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
357                 return ATOM_USER;
358         else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
359                 return ATOM_KEY;
360         else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
361                 return ATOM_ALBUM_ARTIST;
362         else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
363                 return ATOM_DESCRIPTION;
364         else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
365                 return ATOM_PODCAST;
366         else
367                 return ATOM_UNKNOWN;
368 }
369
370 /* read atom header, return atom size, atom size is with header included */
371 static uint64_t atom_read_header(struct mp4 *f, uint8_t * atom_type,
372                                 uint8_t * header_size)
373 {
374         uint64_t size;
375         int32_t ret;
376         int8_t atom_header[8];
377
378         ret = read_data(f, atom_header, 8);
379         if (ret != 8)
380                 return 0;
381
382         size = read_u32_be(atom_header);
383         *header_size = 8;
384
385         /* check for 64 bit atom size */
386         if (size == 1) {
387                 *header_size = 16;
388                 size = read_int64(f);
389         }
390         *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
391                 atom_header[6], atom_header[7]);
392         return size;
393 }
394
395 static int64_t get_position(const struct mp4 *f)
396 {
397         return f->current_position;
398 }
399
400 static int need_parse_when_meta_only(uint8_t atom_type)
401 {
402         switch (atom_type) {
403         case ATOM_EDTS:
404         case ATOM_DRMS:
405         case ATOM_SINF:
406         case ATOM_SCHI:
407         case ATOM_STTS:
408         case ATOM_STSZ:
409         case ATOM_STZ2:
410         case ATOM_STCO:
411         case ATOM_STSC:
412         case ATOM_FRMA:
413         case ATOM_IVIV:
414         case ATOM_PRIV:
415                 return 0;
416         default:
417                 return 1;
418         }
419 }
420
421 static int32_t set_position(struct mp4 *f, int64_t position)
422 {
423         f->stream->seek(f->stream->user_data, position);
424         f->current_position = position;
425
426         return 0;
427 }
428
429 static void track_add(struct mp4 *f)
430 {
431         f->total_tracks++;
432
433         if (f->total_tracks > MAX_TRACKS) {
434                 f->total_tracks = 0;
435                 f->error++;
436                 return;
437         }
438         f->track[f->total_tracks - 1] = para_calloc(sizeof(struct mp4_track));
439 }
440
441 static uint8_t read_char(struct mp4 *f)
442 {
443         uint8_t output;
444         read_data(f, &output, 1);
445         return output;
446 }
447
448 static uint32_t read_int24(struct mp4 *f)
449 {
450         int8_t data[4];
451
452         read_data(f, data, 3);
453         return read_u24_be(data);
454 }
455
456 static uint32_t read_int32(struct mp4 *f)
457 {
458         int8_t data[4];
459
460         read_data(f, data, 4);
461         return read_u32_be(data);
462 }
463
464 static int32_t read_stsz(struct mp4 *f)
465 {
466         int32_t i;
467         struct mp4_track *t;
468
469         if (f->total_tracks == 0)
470                 return f->error++;
471         t = f->track[f->total_tracks - 1];
472         read_char(f);   /* version */
473         read_int24(f);  /* flags */
474         t->stsz_sample_size = read_int32(f);
475         t->stsz_sample_count = read_int32(f);
476         if (t->stsz_sample_size != 0)
477                 return 0;
478         t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
479         for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
480                 t->stsz_table[i] = read_int32(f);
481         return 0;
482 }
483
484 static int32_t read_stts(struct mp4 *f)
485 {
486         int32_t i;
487         struct mp4_track *t;
488
489         /* CVE-2017-9223 */
490         if (f->total_tracks == 0)
491                 return f->error++;
492         t = f->track[f->total_tracks - 1];
493         if (t->stts_entry_count)
494                 return 0;
495         read_char(f);   /* version */
496         read_int24(f);  /* flags */
497         t->stts_entry_count = read_int32(f);
498
499         t->stts_sample_count = para_malloc(t->stts_entry_count
500                 * sizeof(int32_t));
501         t->stts_sample_delta = para_malloc(t->stts_entry_count
502                 * sizeof (int32_t));
503         /* CVE-2017-9254 */
504         for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
505                 t->stts_sample_count[i] = read_int32(f);
506                 t->stts_sample_delta[i] = read_int32(f);
507         }
508         return 1;
509 }
510
511 static int32_t read_ctts(struct mp4 *f)
512 {
513         int32_t i;
514         struct mp4_track *t;
515
516         if (f->total_tracks == 0)
517                 return f->error++;
518         t = f->track[f->total_tracks - 1];
519         if (t->ctts_entry_count)
520                 return 0;
521
522         read_char(f);   /* version */
523         read_int24(f);  /* flags */
524         t->ctts_entry_count = read_int32(f);
525
526         t->ctts_sample_count = para_malloc(t->ctts_entry_count
527                 * sizeof (int32_t));
528         t->ctts_sample_offset = para_malloc(t->ctts_entry_count
529                 * sizeof (int32_t));
530
531         /* CVE-2017-9257 */
532         for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
533                 t->ctts_sample_count[i] = read_int32(f);
534                 t->ctts_sample_offset[i] = read_int32(f);
535         }
536         return 1;
537 }
538
539 static int32_t read_stsc(struct mp4 *f)
540 {
541         int32_t i;
542         struct mp4_track *t;
543
544         if (f->total_tracks == 0)
545                 return f->error++;
546         t = f->track[f->total_tracks - 1];
547
548         read_char(f);   /* version */
549         read_int24(f);  /* flags */
550         t->stsc_entry_count = read_int32(f);
551         t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
552         t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
553                 * sizeof (int32_t));
554         t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
555                 sizeof (int32_t));
556
557         /* CVE-2017-9255 */
558         for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
559                 t->stsc_first_chunk[i] = read_int32(f);
560                 t->stsc_samples_per_chunk[i] = read_int32(f);
561                 t->stsc_sample_desc_index[i] = read_int32(f);
562         }
563         return 0;
564 }
565
566 static int32_t read_stco(struct mp4 *f)
567 {
568         int32_t i;
569         struct mp4_track *t;
570
571         if (f->total_tracks == 0)
572                 return f->error++;
573         t = f->track[f->total_tracks - 1];
574
575         read_char(f);   /* version */
576         read_int24(f);  /* flags */
577         t->stco_entry_count = read_int32(f);
578         t->stco_chunk_offset = para_malloc(t->stco_entry_count
579                 * sizeof(int32_t));
580         /* CVE-2017-9256 */
581         for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
582                 t->stco_chunk_offset[i] = read_int32(f);
583         return 0;
584 }
585
586 static uint16_t read_int16(struct mp4 *f)
587 {
588         int8_t data[2];
589
590         read_data(f, data, 2);
591         return read_u16_be(data);
592 }
593
594 static uint32_t read_mp4_descr_length(struct mp4 *f)
595 {
596         uint8_t b;
597         uint8_t numBytes = 0;
598         uint32_t length = 0;
599
600         do {
601                 b = read_char(f);
602                 numBytes++;
603                 length = (length << 7) | (b & 0x7F);
604         } while ((b & 0x80) && numBytes < 4);
605
606         return length;
607 }
608 static int32_t read_esds(struct mp4 *f)
609 {
610         uint8_t tag;
611         uint32_t temp;
612         struct mp4_track *t;
613
614         if (f->total_tracks == 0)
615                 return f->error++;
616         t = f->track[f->total_tracks - 1];
617         read_char(f);   /* version */
618         read_int24(f);  /* flags */
619         /* get and verify ES_DescrTag */
620         tag = read_char(f);
621         if (tag == 0x03) {
622                 /* read length */
623                 if (read_mp4_descr_length(f) < 5 + 15) {
624                         return 1;
625                 }
626                 /* skip 3 bytes */
627                 read_int24(f);
628         } else {
629                 /* skip 2 bytes */
630                 read_int16(f);
631         }
632
633         /* get and verify DecoderConfigDescrTab */
634         if (read_char(f) != 0x04) {
635                 return 1;
636         }
637
638         /* read length */
639         temp = read_mp4_descr_length(f);
640         if (temp < 13)
641                 return 1;
642
643         t->audioType = read_char(f);
644         read_int32(f);  //0x15000414 ????
645         t->maxBitrate = read_int32(f);
646         t->avgBitrate = read_int32(f);
647
648         /* get and verify DecSpecificInfoTag */
649         if (read_char(f) != 0x05) {
650                 return 1;
651         }
652
653         /* read length */
654         t->decoderConfigLen = read_mp4_descr_length(f);
655         free(t->decoderConfig);
656         t->decoderConfig = para_malloc(t->decoderConfigLen);
657         read_data(f, t->decoderConfig, t->decoderConfigLen);
658         /* will skip the remainder of the atom */
659         return 0;
660 }
661
662 static int32_t read_mp4a(struct mp4 *f)
663 {
664         int32_t i;
665         uint8_t atom_type = 0;
666         uint8_t header_size = 0;
667         struct mp4_track *t;
668
669         if (f->total_tracks == 0)
670                 return f->error++;
671         t = f->track[f->total_tracks - 1];
672
673         for (i = 0; i < 6; i++) {
674                 read_char(f);   /* reserved */
675         }
676         /* data_reference_index */ read_int16(f);
677
678         read_int32(f);  /* reserved */
679         read_int32(f);  /* reserved */
680
681         t->channelCount = read_int16(f);
682         t->sampleSize = read_int16(f);
683
684         read_int16(f);
685         read_int16(f);
686
687         t->sampleRate = read_int16(f);
688
689         read_int16(f);
690
691         atom_read_header(f, &atom_type, &header_size);
692         if (atom_type == ATOM_ESDS)
693                 read_esds(f);
694         return 0;
695 }
696
697 static int32_t read_stsd(struct mp4 *f)
698 {
699         int32_t i;
700         uint8_t header_size = 0;
701         struct mp4_track *t;
702
703         /* CVE-2017-9218 */
704         if (f->total_tracks == 0)
705                 return f->error++;
706         t = f->track[f->total_tracks - 1];
707
708         read_char(f);   /* version */
709         read_int24(f);  /* flags */
710
711         t->stsd_entry_count = read_int32(f);
712
713         /* CVE-2017-9253 */
714         for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
715                 uint64_t skip = get_position(f);
716                 uint64_t size;
717                 uint8_t atom_type = 0;
718                 size = atom_read_header(f, &atom_type, &header_size);
719                 skip += size;
720
721                 if (atom_type == ATOM_MP4A) {
722                         t->type = TRACK_AUDIO;
723                         read_mp4a(f);
724                 } else if (atom_type == ATOM_MP4V) {
725                         t->type = TRACK_VIDEO;
726                 } else if (atom_type == ATOM_MP4S) {
727                         t->type = TRACK_SYSTEM;
728                 } else {
729                         t->type = TRACK_UNKNOWN;
730                 }
731                 set_position(f, skip);
732         }
733
734         return 0;
735 }
736
737 static int32_t read_mvhd(struct mp4 *f)
738 {
739         int32_t i;
740
741         read_char(f);   /* version */
742         read_int24(f);  /* flags */
743         read_int32(f); /* creation_time */
744         read_int32(f); /* modification_time */
745         f->time_scale = read_int32(f);
746         f->duration = read_int32(f);
747         read_int32(f); /* preferred_rate */
748         read_int16(f); /* preferred_volume */
749         for (i = 0; i < 10; i++)
750                 read_char(f); /* reserved */
751         for (i = 0; i < 9; i++)
752                 read_int32(f); /* matrix */
753         read_int32(f); /* preview_time */
754         read_int32(f); /* preview_duration */
755         read_int32(f); /* poster_time */
756         read_int32(f); /* selection_time */
757         read_int32(f); /* selection_duration */
758         read_int32(f); /* current_time */
759         read_int32(f); /* next_track_id */
760         return 0;
761 }
762
763 static int32_t tag_add_field(struct mp4_metadata *tags, const char *item,
764                 const char *value, int32_t len)
765 {
766         if (!item || (item && !*item) || !value)
767                 return 0;
768         tags->tags = para_realloc(tags->tags,
769                 (tags->count + 1) * sizeof(struct mp4_tag));
770         tags->tags[tags->count].item = para_strdup(item);
771         tags->tags[tags->count].len = len;
772         if (len >= 0) {
773                 tags->tags[tags->count].value = para_malloc(len + 1);
774                 memcpy(tags->tags[tags->count].value, value, len);
775                 tags->tags[tags->count].value[len] = 0;
776         } else {
777                 tags->tags[tags->count].value = para_strdup(value);
778         }
779         tags->count++;
780         return 1;
781 }
782
783 static const char *ID3v1GenreList[] = {
784         "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
785         "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
786         "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
787         "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
788         "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
789         "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
790         "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
791         "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
792         "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
793         "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
794         "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
795         "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
796         "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
797         "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
798         "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
799         "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
800         "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
801         "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
802         "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
803         "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
804         "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
805         "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
806         "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
807         "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
808         "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
809         "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
810         "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
811         "Anime", "JPop", "SynthPop",
812 };
813
814 static const char *meta_index_to_genre(uint32_t idx)
815 {
816         if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
817                 return ID3v1GenreList[idx - 1];
818         } else {
819                 return 0;
820         }
821 }
822
823 static char *read_string(struct mp4 *f, uint32_t length)
824 {
825         char *str = para_malloc(length + 1);
826         if ((uint32_t)read_data(f, str, length) != length) {
827                 free(str);
828                 str = NULL;
829         } else
830                 str[length] = 0;
831         return str;
832 }
833
834 static int32_t set_metadata_name(uint8_t atom_type, char **name)
835 {
836         static char *tag_names[] = {
837                 "unknown", "title", "artist", "writer", "album",
838                 "date", "tool", "comment", "genre", "track",
839                 "disc", "compilation", "genre", "tempo", "cover",
840                 "album_artist", "contentgroup", "lyrics", "description",
841                 "network", "show", "episodename",
842                 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
843                 "sortwriter", "sortshow",
844                 "season", "episode", "podcast"
845         };
846         uint8_t tag_idx = 0;
847
848         switch (atom_type) {
849         case ATOM_TITLE:
850                 tag_idx = 1;
851                 break;
852         case ATOM_ARTIST:
853                 tag_idx = 2;
854                 break;
855         case ATOM_WRITER:
856                 tag_idx = 3;
857                 break;
858         case ATOM_ALBUM:
859                 tag_idx = 4;
860                 break;
861         case ATOM_DATE:
862                 tag_idx = 5;
863                 break;
864         case ATOM_TOOL:
865                 tag_idx = 6;
866                 break;
867         case ATOM_COMMENT:
868                 tag_idx = 7;
869                 break;
870         case ATOM_GENRE1:
871                 tag_idx = 8;
872                 break;
873         case ATOM_TRACK:
874                 tag_idx = 9;
875                 break;
876         case ATOM_DISC:
877                 tag_idx = 10;
878                 break;
879         case ATOM_COMPILATION:
880                 tag_idx = 11;
881                 break;
882         case ATOM_GENRE2:
883                 tag_idx = 12;
884                 break;
885         case ATOM_TEMPO:
886                 tag_idx = 13;
887                 break;
888         case ATOM_COVER:
889                 tag_idx = 14;
890                 break;
891         case ATOM_ALBUM_ARTIST:
892                 tag_idx = 15;
893                 break;
894         case ATOM_CONTENTGROUP:
895                 tag_idx = 16;
896                 break;
897         case ATOM_LYRICS:
898                 tag_idx = 17;
899                 break;
900         case ATOM_DESCRIPTION:
901                 tag_idx = 18;
902                 break;
903         case ATOM_NETWORK:
904                 tag_idx = 19;
905                 break;
906         case ATOM_SHOW:
907                 tag_idx = 20;
908                 break;
909         case ATOM_EPISODENAME:
910                 tag_idx = 21;
911                 break;
912         case ATOM_SORTTITLE:
913                 tag_idx = 22;
914                 break;
915         case ATOM_SORTALBUM:
916                 tag_idx = 23;
917                 break;
918         case ATOM_SORTARTIST:
919                 tag_idx = 24;
920                 break;
921         case ATOM_SORTALBUMARTIST:
922                 tag_idx = 25;
923                 break;
924         case ATOM_SORTWRITER:
925                 tag_idx = 26;
926                 break;
927         case ATOM_SORTSHOW:
928                 tag_idx = 27;
929                 break;
930         case ATOM_SEASON:
931                 tag_idx = 28;
932                 break;
933         case ATOM_EPISODE:
934                 tag_idx = 29;
935                 break;
936         case ATOM_PODCAST:
937                 tag_idx = 30;
938                 break;
939         default:
940                 tag_idx = 0;
941                 break;
942         }
943
944         *name = para_strdup(tag_names[tag_idx]);
945         return 0;
946 }
947
948 static uint32_t min_body_size(uint8_t atom_type)
949 {
950         switch(atom_type) {
951         case ATOM_GENRE2:
952         case ATOM_TEMPO:
953                 return 10;
954         case ATOM_TRACK:
955                 return sizeof (char) /* version */
956                         + sizeof(uint8_t) * 3 /* flags */
957                         + sizeof(uint32_t) /* reserved */
958                         + sizeof(uint16_t) /* leading uint16_t */
959                         + sizeof(uint16_t) /* track */
960                         + sizeof(uint16_t); /* totaltracks */
961         case ATOM_DISC:
962                 return sizeof (char) /* version */
963                         + sizeof(uint8_t) * 3 /* flags */
964                         + sizeof(uint32_t) /* reserved */
965                         + sizeof(uint16_t) /* disc */
966                         + sizeof(uint16_t); /* totaldiscs */
967         default: assert(false);
968         }
969 }
970
971 static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
972 {
973         uint8_t atom_type;
974         uint8_t header_size = 0;
975         uint64_t subsize, sumsize;
976         char *name = NULL;
977         char *data = NULL;
978         uint32_t done = 0;
979         uint32_t len = 0;
980         uint64_t destpos;
981
982         for (
983                 sumsize = 0;
984                 sumsize < size && !f->stream->read_error; /* CVE-2017-9222 */
985                 set_position(f, destpos), sumsize += subsize
986         ) {
987                 subsize = atom_read_header(f, &atom_type, &header_size);
988                 destpos = get_position(f) + subsize - header_size;
989                 if (done)
990                         continue;
991                 if (atom_type == ATOM_NAME) {
992                         read_char(f);   /* version */
993                         read_int24(f);  /* flags */
994                         free(name);
995                         name = read_string(f, subsize - (header_size + 4));
996                         continue;
997                 }
998                 if (atom_type != ATOM_DATA)
999                         continue;
1000                 read_char(f);   /* version */
1001                 read_int24(f);  /* flags */
1002                 read_int32(f);  /* reserved */
1003
1004                 /* some need special attention */
1005                 if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
1006                         uint16_t val;
1007                         if (subsize - header_size < min_body_size(parent))
1008                                 continue;
1009                         val = read_int16(f);
1010                         if (parent == ATOM_TEMPO) {
1011                                 char temp[16];
1012                                 sprintf(temp, "%.5u BPM", val);
1013                                 tag_add_field(&(f-> tags), "tempo",
1014                                         temp, -1);
1015                         } else {
1016                                 const char *tmp = meta_index_to_genre(val);
1017                                 if (tmp)
1018                                         tag_add_field (&(f->tags),
1019                                                 "genre", tmp, -1);
1020                         }
1021                         done = 1;
1022                 } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
1023                         uint16_t index, total;
1024                         char temp[32];
1025                         if (subsize - header_size < min_body_size(parent))
1026                                 continue;
1027                         read_int16(f);
1028                         index = read_int16(f);
1029                         total = read_int16(f);
1030                         if (parent == ATOM_TRACK)
1031                                 read_int16(f);
1032                         sprintf(temp, "%d", index);
1033                         tag_add_field(&(f->tags), parent == ATOM_TRACK?
1034                                 "track" : "disc", temp, -1);
1035                         if (total > 0) {
1036                                 sprintf(temp, "%d", total);
1037                                 tag_add_field(& (f-> tags),
1038                                         parent == ATOM_TRACK?
1039                                         "totaltracks" : "totaldiscs", temp, -1);
1040                         }
1041                         done = 1;
1042                 } else {
1043                         free(data);
1044                         data = read_string(f, subsize - (header_size + 8));
1045                         len = subsize - (header_size + 8);
1046                 }
1047         }
1048         if (data) {
1049                 if (!done) {
1050                         if (name == NULL)
1051                                 set_metadata_name(parent , &name);
1052                         if (name)
1053                                 tag_add_field(&(f->tags), name, data, len);
1054                 }
1055
1056                 free(data);
1057         }
1058         free(name);
1059         return 1;
1060 }
1061
1062 static int32_t read_mdhd(struct mp4 *f)
1063 {
1064         uint32_t version;
1065         struct mp4_track *t;
1066
1067         /* CVE-2017-9221 */
1068         if (f->total_tracks == 0)
1069                 return f->error++;
1070         t = f->track[f->total_tracks - 1];
1071
1072         version = read_int32(f);
1073         if (version == 1) {
1074                 read_int64(f); //creation-time
1075                 read_int64(f); //modification-time
1076                 t->timeScale = read_int32(f); //timescale
1077                 t->duration = read_int64(f); //duration
1078         } else { //version == 0
1079                 uint32_t temp;
1080
1081                 read_int32(f);  //creation-time
1082                 read_int32(f);  //modification-time
1083                 t->timeScale = read_int32(f); //timescale
1084                 temp = read_int32(f);
1085                 t->duration = (temp == (uint32_t) (-1))?
1086                         (uint64_t) (-1) : (uint64_t) (temp);
1087         }
1088         read_int16(f);
1089         read_int16(f);
1090         return 1;
1091 }
1092
1093 static int32_t parse_metadata(struct mp4 *f, int32_t size)
1094 {
1095         uint64_t subsize, sumsize = 0;
1096         uint8_t atom_type;
1097         uint8_t header_size = 0;
1098
1099         while (sumsize < size) {
1100                 subsize = atom_read_header(f, &atom_type, &header_size);
1101                 if (subsize == 0)
1102                         break;
1103                 parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
1104                 sumsize += subsize;
1105         }
1106
1107         return 0;
1108 }
1109
1110 static int32_t read_meta(struct mp4 *f, uint64_t size)
1111 {
1112         uint64_t subsize, sumsize = 0;
1113         uint8_t atom_type;
1114         uint8_t header_size = 0;
1115
1116         read_char(f);   /* version */
1117         read_int24(f);  /* flags */
1118
1119         while (sumsize < (size - (header_size + 4))) {
1120                 subsize = atom_read_header(f, &atom_type, &header_size);
1121                 if (subsize <= header_size + 4)
1122                         return 1;
1123                 if (atom_type == ATOM_ILST) {
1124                         parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1125                 } else {
1126                         set_position(f, get_position(f) + subsize - header_size);
1127                 }
1128                 sumsize += subsize;
1129         }
1130
1131         return 0;
1132 }
1133
1134 static int32_t atom_read(struct mp4 *f, int32_t size, uint8_t atom_type)
1135 {
1136         uint64_t dest_position = get_position(f) + size - 8;
1137         if (atom_type == ATOM_STSZ) {
1138                 /* sample size box */
1139                 read_stsz(f);
1140         } else if (atom_type == ATOM_STTS) {
1141                 /* time to sample box */
1142                 read_stts(f);
1143         } else if (atom_type == ATOM_CTTS) {
1144                 /* composition offset box */
1145                 read_ctts(f);
1146         } else if (atom_type == ATOM_STSC) {
1147                 /* sample to chunk box */
1148                 read_stsc(f);
1149         } else if (atom_type == ATOM_STCO) {
1150                 /* chunk offset box */
1151                 read_stco(f);
1152         } else if (atom_type == ATOM_STSD) {
1153                 /* sample description box */
1154                 read_stsd(f);
1155         } else if (atom_type == ATOM_MVHD) {
1156                 /* movie header box */
1157                 read_mvhd(f);
1158         } else if (atom_type == ATOM_MDHD) {
1159                 /* track header */
1160                 read_mdhd(f);
1161         } else if (atom_type == ATOM_META) {
1162                 /* iTunes Metadata box */
1163                 read_meta(f, size);
1164         }
1165
1166         set_position(f, dest_position);
1167         return 0;
1168 }
1169
1170 /* parse atoms that are sub atoms of other atoms */
1171 static int32_t parse_sub_atoms(struct mp4 *f, uint64_t total_size, int meta_only)
1172 {
1173         uint64_t size;
1174         uint8_t atom_type = 0;
1175         uint64_t counted_size = 0;
1176         uint8_t header_size = 0;
1177
1178         while (counted_size < total_size) {
1179                 size = atom_read_header(f, &atom_type, &header_size);
1180                 counted_size += size;
1181
1182                 /* check for end of file */
1183                 if (size == 0)
1184                         break;
1185
1186                 /* we're starting to read a new track, update index,
1187                  * so that all data and tables get written in the right place
1188                  */
1189                 if (atom_type == ATOM_TRAK)
1190                         track_add(f);
1191                 /* parse subatoms */
1192                 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1193                         set_position(f, get_position(f) + size - header_size);
1194                 } else if (atom_type < SUBATOMIC) {
1195                         parse_sub_atoms(f, size - header_size, meta_only);
1196                 } else {
1197                         atom_read(f, (uint32_t) size, atom_type);
1198                 }
1199         }
1200
1201         return 0;
1202 }
1203
1204 /* parse root atoms */
1205 static int32_t parse_atoms(struct mp4 *f, int meta_only)
1206 {
1207         uint64_t size;
1208         uint8_t atom_type = 0;
1209         uint8_t header_size = 0;
1210
1211         f->file_size = 0;
1212         f->stream->read_error = 0;
1213
1214         while ((size =
1215                 atom_read_header(f, &atom_type, &header_size)) != 0) {
1216                 f->file_size += size;
1217                 f->last_atom = atom_type;
1218
1219                 if (atom_type == ATOM_MOOV && size > header_size) {
1220                         f->moov_offset = get_position(f) - header_size;
1221                         f->moov_size = size;
1222                 }
1223
1224                 /* parse subatoms */
1225                 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1226                         set_position(f, get_position(f) + size - header_size);
1227                 } else if (atom_type < SUBATOMIC) {
1228                         parse_sub_atoms(f, size - header_size, meta_only);
1229                 } else {
1230                         /* skip this atom */
1231                         set_position(f, get_position(f) + size - header_size);
1232                 }
1233         }
1234
1235         return 0;
1236 }
1237
1238 struct mp4 *mp4_open_read(struct mp4_callback *f)
1239 {
1240         struct mp4 *ff = para_calloc(sizeof(struct mp4));
1241
1242         ff->stream = f;
1243
1244         parse_atoms(ff, 0);
1245
1246         if (ff->error) {
1247                 free(ff);
1248                 ff = NULL;
1249         }
1250
1251         return ff;
1252 }
1253
1254 static int32_t tag_delete(struct mp4_metadata *tags)
1255 {
1256         uint32_t i;
1257
1258         for (i = 0; i < tags->count; i++) {
1259                 free(tags->tags[i].item);
1260                 free(tags->tags[i].value);
1261         }
1262         free(tags->tags);
1263         tags->tags = NULL;
1264         tags->count = 0;
1265
1266         return 0;
1267 }
1268
1269 void mp4_close(struct mp4 *ff)
1270 {
1271         int32_t i;
1272
1273         for (i = 0; i < ff->total_tracks; i++) {
1274                 if (ff->track[i]) {
1275                         free(ff->track[i]->stsz_table);
1276                         free(ff->track[i]->stts_sample_count);
1277                         free(ff->track[i]->stts_sample_delta);
1278                         free(ff->track[i]->stsc_first_chunk);
1279                         free(ff->track[i]->stsc_samples_per_chunk);
1280                         free(ff->track[i]->stsc_sample_desc_index);
1281                         free(ff->track[i]->stco_chunk_offset);
1282                         free(ff->track[i]->decoderConfig);
1283                         free(ff->track[i]->ctts_sample_count);
1284                         free(ff->track[i]->ctts_sample_offset);
1285                         free(ff->track[i]);
1286                 }
1287         }
1288
1289         tag_delete(&(ff->tags));
1290         free(ff);
1291 }
1292
1293 static int32_t chunk_of_sample(const struct mp4 *f, int32_t track,
1294                 int32_t sample, int32_t *chunk_sample, int32_t *chunk)
1295 {
1296         int32_t total_entries = 0;
1297         int32_t chunk2entry;
1298         int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1299
1300         *chunk_sample = 0;
1301         *chunk = 1;
1302         if (f->track[track] == NULL) {
1303                 return -1;
1304         }
1305
1306         total_entries = f->track[track]->stsc_entry_count;
1307
1308         chunk1 = 1;
1309         chunk1samples = 0;
1310         chunk2entry = 0;
1311
1312         do {
1313                 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1314                 *chunk = chunk2 - chunk1;
1315                 range_samples = *chunk * chunk1samples;
1316
1317                 if (sample < total + range_samples)
1318                         break;
1319
1320                 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1321                 chunk1 = chunk2;
1322
1323                 if (chunk2entry < total_entries) {
1324                         chunk2entry++;
1325                         total += range_samples;
1326                 }
1327         } while (chunk2entry < total_entries);
1328
1329         if (chunk1samples)
1330                 *chunk = (sample - total) / chunk1samples + chunk1;
1331         else
1332                 *chunk = 1;
1333
1334         *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1335
1336         return 0;
1337 }
1338
1339 static int32_t chunk_to_offset(const struct mp4 *f, int32_t track,
1340                 int32_t chunk)
1341 {
1342         const struct mp4_track *p_track = f->track[track];
1343
1344         if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1345                 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1346                                                   1];
1347         } else if (p_track->stco_entry_count) {
1348                 return p_track->stco_chunk_offset[chunk - 1];
1349         } else {
1350                 return 8;
1351         }
1352
1353         return 0;
1354 }
1355
1356 static int32_t sample_range_size(const struct mp4 *f, int32_t track,
1357                 int32_t chunk_sample, int32_t sample)
1358 {
1359         int32_t i, total;
1360         const struct mp4_track *p_track = f->track[track];
1361
1362         if (p_track->stsz_sample_size) {
1363                 return (sample - chunk_sample) * p_track->stsz_sample_size;
1364         } else {
1365                 if (sample >= p_track->stsz_sample_count)
1366                         return 0;       //error
1367
1368                 for (i = chunk_sample, total = 0; i < sample; i++) {
1369                         total += p_track->stsz_table[i];
1370                 }
1371         }
1372
1373         return total;
1374 }
1375
1376 static int32_t sample_to_offset(const struct mp4 *f, int32_t track,
1377                 int32_t sample)
1378 {
1379         int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1380
1381         chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1382
1383         chunk_offset1 = chunk_to_offset(f, track, chunk);
1384         chunk_offset2 = chunk_offset1 + sample_range_size(f,
1385                 track, chunk_sample, sample);
1386         return chunk_offset2;
1387 }
1388
1389 /**
1390  * Return the number of milliseconds of the given track.
1391  *
1392  * \param f As returned by \ref mp4_open_read(), must not be NULL.
1393  * \param track Between zero and the value returned by \ref mp4_total_tracks().
1394  *
1395  * The function returns zero if the audio file is of zero length or contains a
1396  * corrupt track header.
1397  */
1398 uint64_t mp4_get_duration(const struct mp4 *f, int32_t track)
1399 {
1400         const struct mp4_track *t = f->track[track];
1401
1402         if (t->timeScale == 0)
1403                 return 0;
1404         return t->duration * 1000 / t->timeScale;
1405 }
1406
1407 /**
1408  * Check whether the given track number corresponds to an audio track.
1409  *
1410  * \param f See \ref mp4_get_duration().
1411  * \param track See \ref mp4_get_duration().
1412  *
1413  * Besides audio tracks, an mp4 file may contain video and system tracks. For
1414  * those the function returns false.
1415  */
1416 bool mp4_is_audio_track(const struct mp4 *f, int32_t track)
1417 {
1418         return f->track[track]->type == TRACK_AUDIO;
1419 }
1420
1421 void mp4_set_sample_position(struct mp4 *f, int32_t track, int32_t sample)
1422 {
1423         int32_t offset = sample_to_offset(f, track, sample);
1424         set_position(f, offset);
1425 }
1426
1427 int32_t mp4_get_sample_size(const struct mp4 *f, int track, int sample)
1428 {
1429         const struct mp4_track *t = f->track[track];
1430
1431         if (t->stsz_sample_size != 0)
1432                 return t->stsz_sample_size;
1433         return t->stsz_table[sample];
1434 }
1435
1436 uint32_t mp4_get_sample_rate(const struct mp4 *f, int32_t track)
1437 {
1438         return f->track[track]->sampleRate;
1439 }
1440
1441 uint32_t mp4_get_channel_count(const struct mp4 *f, int32_t track)
1442 {
1443         return f->track[track]->channelCount;
1444 }
1445
1446 int32_t mp4_num_samples(const struct mp4 *f, int32_t track)
1447 {
1448         int32_t i;
1449         int32_t total = 0;
1450
1451         for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1452                 total += f->track[track]->stts_sample_count[i];
1453         }
1454         return total;
1455 }
1456
1457 struct mp4 *mp4_open_meta(struct mp4_callback *f)
1458 {
1459         struct mp4 *ff = para_calloc(sizeof(struct mp4));
1460
1461         ff->stream = f;
1462
1463         parse_atoms(ff, 1);
1464
1465         if (ff->error) {
1466                 free(ff);
1467                 ff = NULL;
1468         }
1469
1470         return ff;
1471 }
1472
1473 int32_t mp4_meta_get_num_items(const struct mp4 *f)
1474 {
1475         return f->tags.count;
1476 }
1477
1478 int32_t mp4_meta_get_by_index(const struct mp4 *f, uint32_t index,
1479                                 char **item, char **value)
1480 {
1481         if (index >= f->tags.count) {
1482                 *item = NULL;
1483                 *value = NULL;
1484                 return 0;
1485         } else {
1486                 *item = para_strdup(f->tags.tags[index].item);
1487                 *value = para_strdup(f->tags.tags[index].value);
1488                 return 1;
1489         }
1490 }
1491
1492 static uint32_t find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1493                           const char *name)
1494 {
1495         uint32_t remaining = size;
1496         uint64_t atom_offset = base;
1497         for (;;) {
1498                 char atom_name[4];
1499                 uint32_t atom_size;
1500
1501                 set_position(f, atom_offset);
1502
1503                 if (remaining < 8)
1504                         break;
1505                 atom_size = read_int32(f);
1506                 if (atom_size > remaining || atom_size < 8)
1507                         break;
1508                 read_data(f, atom_name, 4);
1509
1510                 if (!memcmp(atom_name, name, 4)) {
1511                         set_position(f, atom_offset);
1512                         return 1;
1513                 }
1514
1515                 remaining -= atom_size;
1516                 atom_offset += atom_size;
1517         }
1518         return 0;
1519 }
1520
1521 static uint32_t find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1522                 const char *name, uint32_t extraheaders, const char *name_inside)
1523 {
1524         uint64_t first_base = (uint64_t) (-1);
1525         while (find_atom(f, base, size, name))  //try to find atom <name> with atom <name_inside> in it
1526         {
1527                 uint64_t mybase = get_position(f);
1528                 uint32_t mysize = read_int32(f);
1529
1530                 if (first_base == (uint64_t) (-1))
1531                         first_base = mybase;
1532
1533                 if (mysize < 8 + extraheaders)
1534                         break;
1535
1536                 if (find_atom (f, mybase + (8 + extraheaders),
1537                                 mysize - (8 + extraheaders), name_inside)) {
1538                         set_position(f, mybase);
1539                         return 2;
1540                 }
1541                 base += mysize;
1542                 if (size <= mysize) {
1543                         size = 0;
1544                         break;
1545                 }
1546                 size -= mysize;
1547         }
1548
1549         if (first_base != (uint64_t) (-1))      //wanted atom inside not found
1550         {
1551                 set_position(f, first_base);
1552                 return 1;
1553         } else
1554                 return 0;
1555 }
1556
1557 struct membuffer {
1558         void *data;
1559         unsigned written;
1560         unsigned allocated;
1561         unsigned error;
1562 };
1563
1564 static struct membuffer *membuffer_create(void)
1565 {
1566         const unsigned initial_size = 256;
1567
1568         struct membuffer *buf = para_malloc(sizeof(*buf));
1569         buf->data = para_malloc(initial_size);
1570         buf->written = 0;
1571         buf->allocated = initial_size;
1572         buf->error = buf->data == 0 ? 1 : 0;
1573
1574         return buf;
1575 }
1576
1577 static unsigned membuffer_write(struct membuffer *buf, const void *ptr, unsigned bytes)
1578 {
1579         unsigned dest_size = buf->written + bytes;
1580
1581         if (buf->error)
1582                 return 0;
1583         if (dest_size > buf->allocated) {
1584                 do {
1585                         buf->allocated <<= 1;
1586                 } while (dest_size > buf->allocated);
1587                 buf->data = para_realloc(buf->data, buf->allocated);
1588         }
1589
1590         if (ptr)
1591                 memcpy((char *) buf->data + buf->written, ptr, bytes);
1592         buf->written += bytes;
1593         return bytes;
1594 }
1595
1596 static unsigned membuffer_write_atom_name(struct membuffer *buf, const char *data)
1597 {
1598         return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1599 }
1600
1601 static unsigned membuffer_write_int16(struct membuffer *buf, uint16_t data)
1602 {
1603         uint8_t temp[2];
1604
1605         write_u16_be(temp, data);
1606         return membuffer_write(buf, temp, 2);
1607 }
1608
1609 static unsigned membuffer_write_int32(struct membuffer *buf, uint32_t data)
1610 {
1611         uint8_t temp[4];
1612         write_u32_be(temp, data);
1613         return membuffer_write(buf, temp, 4);
1614 }
1615
1616 static void membuffer_write_track_tag(struct membuffer *buf, const char *name,
1617                 uint32_t index, uint32_t total)
1618 {
1619         membuffer_write_int32(buf,
1620                 8 /*atom header */  + 8 /*data atom header */  +
1621                 8 /*flags + reserved */  + 8 /*actual data */ );
1622         membuffer_write_atom_name(buf, name);
1623         membuffer_write_int32(buf,
1624                 8 /*data atom header */  +
1625                 8 /*flags + reserved */  + 8 /*actual data */ );
1626         membuffer_write_atom_name(buf, "data");
1627         membuffer_write_int32(buf, 0);  //flags
1628         membuffer_write_int32(buf, 0);  //reserved
1629         membuffer_write_int16(buf, 0);
1630         membuffer_write_int16(buf, (uint16_t) index);   //track number
1631         membuffer_write_int16(buf, (uint16_t) total);   //total tracks
1632         membuffer_write_int16(buf, 0);
1633 }
1634
1635 static void membuffer_write_int16_tag(struct membuffer *buf, const char *name,
1636                 uint16_t value)
1637 {
1638         membuffer_write_int32(buf,
1639                 8 /*atom header */  + 8 /*data atom header */  +
1640                 8 /*flags + reserved */  + 2 /*actual data */ );
1641         membuffer_write_atom_name(buf, name);
1642         membuffer_write_int32(buf,
1643                 8 /*data atom header */  +
1644                 8 /*flags + reserved */  + 2 /*actual data */ );
1645         membuffer_write_atom_name(buf, "data");
1646         membuffer_write_int32(buf, 0);  //flags
1647         membuffer_write_int32(buf, 0);  //reserved
1648         membuffer_write_int16(buf, value);      //value
1649 }
1650
1651 static uint32_t myatoi(const char *param)
1652 {
1653         return param ? atoi(param) : 0;
1654 }
1655
1656 static uint32_t meta_genre_to_index(const char *genrestr)
1657 {
1658         unsigned n;
1659         for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1660                 if (!strcasecmp(genrestr, ID3v1GenreList[n]))
1661                         return n + 1;
1662         }
1663         return 0;
1664 }
1665
1666 struct stdmeta_entry {
1667         const char *atom;
1668         const char *name;
1669 };
1670
1671 struct stdmeta_entry stdmetas[] = {
1672         {"\xA9" "nam", "title"},
1673         {"\xA9" "ART", "artist"},
1674         {"\xA9" "wrt", "writer"},
1675         {"\xA9" "alb", "album"},
1676         {"\xA9" "day", "date"},
1677         {"\xA9" "too", "tool"},
1678         {"\xA9" "cmt", "comment"},
1679         {"cpil", "compilation"},
1680         {"covr", "cover"},
1681         {"aART", "album_artist"},
1682 };
1683
1684 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1685 {
1686         unsigned n;
1687         for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1688                 if (!strcasecmp(name, stdmetas[n].name))
1689                         return stdmetas[n].atom;
1690         }
1691         return 0;
1692 }
1693
1694 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1695                 const char *value)
1696 {
1697         uint32_t flags = 1;
1698
1699         /* special check for compilation flag */
1700         if (strcmp(name, "cpil") == 0) {
1701                 flags = 21;
1702         }
1703
1704         membuffer_write_int32(buf,
1705                 8 /*atom header */  + 8 /*data atom header */  +
1706                 8 /*flags + reserved */  + strlen(value));
1707         membuffer_write_atom_name(buf, name);
1708         membuffer_write_int32(buf,
1709                 8 /*data atom header */  +
1710                 8 /*flags + reserved */  + strlen(value));
1711         membuffer_write_atom_name(buf, "data");
1712         membuffer_write_int32(buf, flags);      //flags
1713         membuffer_write_int32(buf, 0);  //reserved
1714         membuffer_write(buf, value, strlen(value));
1715 }
1716
1717 static void membuffer_write_custom_tag(struct membuffer *buf, const char *name,
1718                 const char *value)
1719 {
1720         membuffer_write_int32(buf,
1721                 8 /*atom header */  +
1722                 0x1C /*weirdo itunes atom */  +
1723                 12 /*name atom header */  + strlen(name) +
1724                 16 /*data atom header + flags */  + strlen(value));
1725         membuffer_write_atom_name(buf, "----");
1726         membuffer_write_int32(buf, 0x1C);       //weirdo itunes atom
1727         membuffer_write_atom_name(buf, "mean");
1728         membuffer_write_int32(buf, 0);
1729         membuffer_write(buf, "com.apple.iTunes", 16);
1730         membuffer_write_int32(buf, 12 + strlen(name));
1731         membuffer_write_atom_name(buf, "name");
1732         membuffer_write_int32(buf, 0);
1733         membuffer_write(buf, name, strlen(name));
1734         membuffer_write_int32(buf,
1735                 8 /*data atom header */  +
1736                 8 /*flags + reserved */  + strlen(value));
1737         membuffer_write_atom_name(buf, "data");
1738         membuffer_write_int32(buf, 1);  //flags
1739         membuffer_write_int32(buf, 0);  //reserved
1740         membuffer_write(buf, value, strlen(value));
1741 }
1742
1743 static unsigned membuffer_error(const struct membuffer *buf)
1744 {
1745         return buf->error;
1746 }
1747
1748 static void membuffer_free(struct membuffer *buf)
1749 {
1750         free(buf->data);
1751         free(buf);
1752 }
1753
1754 static unsigned membuffer_get_size(const struct membuffer *buf)
1755 {
1756         return buf->written;
1757 }
1758
1759 static void *membuffer_detach(struct membuffer *buf)
1760 {
1761         void *ret;
1762
1763         if (buf->error)
1764                 return 0;
1765         ret = para_realloc(buf->data, buf->written);
1766         buf->data = 0;
1767         buf->error = 1;
1768         return ret;
1769 }
1770
1771 static uint32_t create_ilst(const struct mp4_metadata *data, void **out_buffer,
1772                 uint32_t * out_size)
1773 {
1774         struct membuffer *buf = membuffer_create();
1775         unsigned metaptr;
1776         char *mask = para_calloc(data->count);
1777         const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1778         const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1779         const char *genre_ptr = 0, *tempo_ptr = 0;
1780
1781         for (metaptr = 0; metaptr < data->count; metaptr++) {
1782                 struct mp4_tag *tag = &data->tags[metaptr];
1783                 if (!strcasecmp(tag->item, "tracknumber")
1784                                 || !strcasecmp(tag->item, "track")) {
1785                         if (tracknumber_ptr == 0)
1786                                 tracknumber_ptr = tag->value;
1787                         mask[metaptr] = 1;
1788                 } else if (!strcasecmp(tag->item, "totaltracks")) {
1789                         if (totaltracks_ptr == 0)
1790                                 totaltracks_ptr = tag->value;
1791                         mask[metaptr] = 1;
1792                 } else if (!strcasecmp(tag->item, "discnumber")
1793                                 || !strcasecmp(tag->item, "disc")) {
1794                         if (discnumber_ptr == 0)
1795                                 discnumber_ptr = tag->value;
1796                         mask[metaptr] = 1;
1797                 } else if (!strcasecmp(tag->item, "totaldiscs")) {
1798                         if (totaldiscs_ptr == 0)
1799                                 totaldiscs_ptr = tag->value;
1800                         mask[metaptr] = 1;
1801                 } else if (!strcasecmp(tag->item, "genre")) {
1802                         if (genre_ptr == 0)
1803                                 genre_ptr = tag->value;
1804                         mask[metaptr] = 1;
1805                 } else if (!strcasecmp(tag->item, "tempo")) {
1806                         if (tempo_ptr == 0)
1807                                 tempo_ptr = tag->value;
1808                         mask[metaptr] = 1;
1809                 }
1810         }
1811
1812         if (tracknumber_ptr)
1813                 membuffer_write_track_tag(buf, "trkn", myatoi(tracknumber_ptr),
1814                          myatoi(totaltracks_ptr));
1815         if (discnumber_ptr)
1816                 membuffer_write_track_tag(buf, "disk", myatoi(discnumber_ptr),
1817                          myatoi(totaldiscs_ptr));
1818         if (tempo_ptr)
1819                 membuffer_write_int16_tag(buf, "tmpo", myatoi(tempo_ptr));
1820
1821         if (genre_ptr) {
1822                 uint32_t index = meta_genre_to_index(genre_ptr);
1823                 if (index == 0)
1824                         membuffer_write_std_tag(buf, "©gen", genre_ptr);
1825                 else
1826                         membuffer_write_int16_tag(buf, "gnre", index);
1827         }
1828         for (metaptr = 0; metaptr < data->count; metaptr++) {
1829                 struct mp4_tag *tag;
1830                 const char *std_meta_atom;
1831
1832                 if (mask[metaptr])
1833                         continue;
1834                 tag = &data->tags[metaptr];
1835                 std_meta_atom = find_standard_meta(tag->item);
1836                 if (std_meta_atom)
1837                         membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1838                 else
1839                         membuffer_write_custom_tag(buf, tag->item, tag->value);
1840         }
1841         free(mask);
1842
1843         if (membuffer_error(buf)) {
1844                 membuffer_free(buf);
1845                 return 0;
1846         }
1847
1848         *out_size = membuffer_get_size(buf);
1849         *out_buffer = membuffer_detach(buf);
1850         membuffer_free(buf);
1851
1852         return 1;
1853 }
1854
1855 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1856                           const void *data)
1857 {
1858         membuffer_write_int32(buf, size + 8);
1859         membuffer_write_atom_name(buf, name);
1860         membuffer_write(buf, data, size);
1861 }
1862
1863 static void *membuffer_get_ptr(const struct membuffer *buf)
1864 {
1865         return buf->data;
1866 }
1867
1868 static void membuffer_set_error(struct membuffer *buf)
1869 {
1870         buf->error = 1;
1871 }
1872
1873 static unsigned membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1874                 unsigned bytes)
1875 {
1876         unsigned oldsize;
1877         void *bufptr;
1878
1879         oldsize = membuffer_get_size(buf);
1880         if (membuffer_write(buf, 0, bytes) != bytes)
1881                 return 0;
1882
1883         bufptr = membuffer_get_ptr(buf);
1884         if (bufptr == 0)
1885                 return 0;
1886
1887         if ((unsigned)read_data(src, (char *) bufptr + oldsize, bytes) !=
1888                 bytes) {
1889                 membuffer_set_error(buf);
1890                 return 0;
1891         }
1892
1893         return bytes;
1894 }
1895
1896 static uint32_t create_meta(const struct mp4_metadata *data, void **out_buffer,
1897                 uint32_t * out_size)
1898 {
1899         struct membuffer *buf;
1900         uint32_t ilst_size;
1901         void *ilst_buffer;
1902
1903         if (!create_ilst(data, &ilst_buffer, &ilst_size))
1904                 return 0;
1905
1906         buf = membuffer_create();
1907
1908         membuffer_write_int32(buf, 0);
1909         membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1910         free(ilst_buffer);
1911
1912         *out_size = membuffer_get_size(buf);
1913         *out_buffer = membuffer_detach(buf);
1914         membuffer_free(buf);
1915         return 1;
1916 }
1917
1918 static uint32_t create_udta(const struct mp4_metadata *data, void **out_buffer,
1919 uint32_t * out_size)
1920 {
1921         struct membuffer *buf;
1922         uint32_t meta_size;
1923         void *meta_buffer;
1924
1925         if (!create_meta(data, &meta_buffer, &meta_size))
1926                 return 0;
1927
1928         buf = membuffer_create();
1929
1930         membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1931
1932         free(meta_buffer);
1933
1934         *out_size = membuffer_get_size(buf);
1935         *out_buffer = membuffer_detach(buf);
1936         membuffer_free(buf);
1937         return 1;
1938 }
1939
1940 static uint32_t fix_byte_order_32(uint32_t src)
1941 {
1942         return read_u32_be(&src);
1943 }
1944
1945 static uint32_t modify_moov(struct mp4 *f, const struct mp4_metadata *data,
1946                 void **out_buffer, uint32_t * out_size)
1947 {
1948         uint64_t total_base = f->moov_offset + 8;
1949         uint32_t total_size = (uint32_t) (f->moov_size - 8);
1950
1951         uint64_t udta_offset, meta_offset, ilst_offset;
1952         uint32_t udta_size, meta_size, ilst_size;
1953
1954         uint32_t new_ilst_size;
1955         void *new_ilst_buffer;
1956
1957         uint8_t *p_out;
1958         int32_t size_delta;
1959
1960         if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1961                 struct membuffer *buf;
1962                 void *new_udta_buffer;
1963                 uint32_t new_udta_size;
1964                 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1965                         return 0;
1966
1967                 buf = membuffer_create();
1968                 set_position(f, total_base);
1969                 membuffer_transfer_from_file(buf, f, total_size);
1970
1971                 membuffer_write_atom(buf, "udta", new_udta_size,
1972                         new_udta_buffer);
1973
1974                 free(new_udta_buffer);
1975
1976                 *out_size = membuffer_get_size(buf);
1977                 *out_buffer = membuffer_detach(buf);
1978                 membuffer_free(buf);
1979                 return 1;
1980         } else {
1981                 udta_offset = get_position(f);
1982                 udta_size = read_int32(f);
1983                 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
1984                         struct membuffer *buf;
1985                         void *new_meta_buffer;
1986                         uint32_t new_meta_size;
1987                         if (!create_meta(data, &new_meta_buffer, &new_meta_size))
1988                                 return 0;
1989
1990                         buf = membuffer_create();
1991                         set_position(f, total_base);
1992                         membuffer_transfer_from_file(buf, f,
1993                                 (uint32_t)(udta_offset - total_base));
1994
1995                         membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1996                         membuffer_write_atom_name(buf, "udta");
1997                         membuffer_transfer_from_file(buf, f, udta_size);
1998
1999                         membuffer_write_atom(buf, "meta", new_meta_size,
2000                                 new_meta_buffer);
2001                         free(new_meta_buffer);
2002
2003                         *out_size = membuffer_get_size(buf);
2004                         *out_buffer = membuffer_detach(buf);
2005                         membuffer_free(buf);
2006                         return 1;
2007                 }
2008                 meta_offset = get_position(f);
2009                 meta_size = read_int32(f);
2010                 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2011                         return 0;       //shouldn't happen, find_atom_v2 above takes care of it
2012                 ilst_offset = get_position(f);
2013                 ilst_size = read_int32(f);
2014
2015                 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2016                         return 0;
2017
2018                 size_delta = new_ilst_size - (ilst_size - 8);
2019
2020                 *out_size = total_size + size_delta;
2021                 *out_buffer = para_malloc(*out_size);
2022                 p_out = (uint8_t *) * out_buffer;
2023
2024                 set_position(f, total_base);
2025                 read_data(f, p_out,
2026                                 (uint32_t) (udta_offset - total_base));
2027                 p_out += (uint32_t) (udta_offset - total_base);
2028                 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2029                 p_out += 4;
2030                 read_data(f, p_out, 4);
2031                 p_out += 4;
2032                 read_data(f, p_out,
2033                                 (uint32_t) (meta_offset - udta_offset - 8));
2034                 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2035                 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2036                 p_out += 4;
2037                 read_data(f, p_out, 4);
2038                 p_out += 4;
2039                 read_data(f, p_out,
2040                                 (uint32_t) (ilst_offset - meta_offset - 8));
2041                 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2042                 *(uint32_t *) p_out = fix_byte_order_32(read_int32(f) + size_delta);
2043                 p_out += 4;
2044                 read_data(f, p_out, 4);
2045                 p_out += 4;
2046
2047                 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2048                 p_out += new_ilst_size;
2049
2050                 set_position(f, ilst_offset + ilst_size);
2051                 read_data(f, p_out, (uint32_t) (total_size
2052                         - (ilst_offset - total_base) - ilst_size));
2053
2054                 free(new_ilst_buffer);
2055         }
2056         return 1;
2057 }
2058
2059 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
2060 {
2061         int32_t result = 1;
2062
2063         result = f->stream->write(f->stream->user_data, data, size);
2064
2065         f->current_position += size;
2066
2067         return result;
2068 }
2069
2070 static int32_t write_int32(struct mp4 *f, uint32_t data)
2071 {
2072         int8_t temp[4];
2073         write_u32_be(temp, data);
2074         return write_data(f, temp, sizeof(temp));
2075 }
2076
2077 static int32_t truncate_stream(struct mp4 *f)
2078 {
2079         return f->stream->truncate(f->stream->user_data);
2080 }
2081
2082 int32_t mp4_meta_update(struct mp4_callback *f, const struct mp4_metadata *data)
2083 {
2084         void *new_moov_data;
2085         uint32_t new_moov_size;
2086
2087         struct mp4 *ff = para_calloc(sizeof(struct mp4));
2088         ff->stream = f;
2089         set_position(ff, 0);
2090
2091         parse_atoms(ff, 1);
2092
2093         if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2094                 mp4_close(ff);
2095                 return 0;
2096         }
2097
2098         /* copy moov atom to end of the file */
2099         if (ff->last_atom != ATOM_MOOV) {
2100                 char *free_data = "free";
2101
2102                 /* rename old moov to free */
2103                 set_position(ff, ff->moov_offset + 4);
2104                 write_data(ff, free_data, 4);
2105
2106                 set_position(ff, ff->file_size);
2107                 write_int32(ff, new_moov_size + 8);
2108                 write_data(ff, "moov", 4);
2109                 write_data(ff, new_moov_data, new_moov_size);
2110         } else {
2111                 set_position(ff, ff->moov_offset);
2112                 write_int32(ff, new_moov_size + 8);
2113                 write_data(ff, "moov", 4);
2114                 write_data(ff, new_moov_data, new_moov_size);
2115         }
2116
2117         truncate_stream(ff);
2118
2119         mp4_close(ff);
2120         return 1;
2121 }
2122
2123 /* find a metadata item by name */
2124 /* returns 0 if item found, 1 if no such item */
2125 static int32_t meta_find_by_name(const struct mp4 *f, const char *item,
2126                 char **value)
2127 {
2128         uint32_t i;
2129
2130         for (i = 0; i < f->tags.count; i++) {
2131                 if (!strcasecmp(f->tags.tags[i].item, item)) {
2132                         *value = para_strdup(f->tags.tags[i].value);
2133                         return 1;
2134                 }
2135         }
2136
2137         *value = NULL;
2138
2139         /* not found */
2140         return 0;
2141 }
2142
2143 int32_t mp4_meta_get_artist(const struct mp4 *f, char **value)
2144 {
2145         return meta_find_by_name(f, "artist", value);
2146 }
2147
2148 int32_t mp4_meta_get_title(const struct mp4 *f, char **value)
2149 {
2150         return meta_find_by_name(f, "title", value);
2151 }
2152
2153 int32_t mp4_meta_get_date(const struct mp4 *f, char **value)
2154 {
2155         return meta_find_by_name(f, "date", value);
2156 }
2157
2158 int32_t mp4_meta_get_album(const struct mp4 *f, char **value)
2159 {
2160         return meta_find_by_name(f, "album", value);
2161 }
2162
2163 int32_t mp4_meta_get_comment(const struct mp4 *f, char **value)
2164 {
2165         return meta_find_by_name(f, "comment", value);
2166 }