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