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