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