]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
mp4: Rename atom_read() to parse_leaf_atom().
[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 "error.h"
12 #include "portable_io.h"
13 #include "string.h"
14 #include "mp4.h"
15
16 struct mp4_track {
17         uint16_t channelCount;
18         uint16_t sampleRate;
19
20         /* stsz */
21         uint32_t stsz_sample_size;
22         uint32_t stsz_sample_count;
23         uint32_t *stsz_table;
24
25         /* stts */
26         uint32_t stts_entry_count;
27         uint32_t *stts_sample_count;
28
29         /* stsc */
30         uint32_t stsc_entry_count;
31         uint32_t *stsc_first_chunk;
32         uint32_t *stsc_samples_per_chunk;
33
34         /* stsc */
35         uint32_t stco_entry_count;
36         uint32_t *stco_chunk_offset;
37
38         uint32_t timeScale;
39         uint64_t duration;
40 };
41
42 #define MAX_TRACKS 1024
43
44 struct mp4 {
45         const struct mp4_callback *cb;
46         int64_t current_position;
47
48         uint64_t moov_offset;
49         uint64_t moov_size;
50         uint8_t last_atom;
51         uint64_t file_size;
52
53         /* incremental track index while reading the file */
54         int32_t total_tracks;
55         /* track data */
56         struct mp4_track *track[MAX_TRACKS];
57         /* the first audio track found */
58         struct mp4_track *audio_track;
59
60         /* metadata */
61         struct mp4_metadata meta;
62 };
63
64 /*
65  * Returns -1, 0, or 1 on errors/EOF/success. Partial reads followed by EOF or
66  * read errors are treated as errors.
67  */
68 static int read_data(struct mp4 *f, void *data, size_t size)
69 {
70         while (size > 0) {
71                 ssize_t ret = f->cb->read(f->cb->user_data, data, size);
72                 if (ret < 0 && errno == EINTR)
73                         continue;
74                 /* regard EAGAIN as an error as reads should be blocking. */
75                 if (ret <= 0)
76                         return ret < 0? -1 : 0;
77                 f->current_position += ret;
78                 size -= ret;
79         }
80         return 1;
81 }
82
83 static int read_int64(struct mp4 *f, uint64_t *result)
84 {
85         uint8_t data[8];
86         int ret = read_data(f, data, 8);
87
88         if (ret > 0 && result)
89                 *result = read_u64_be(data);
90         return ret;
91 }
92
93 static int read_int32(struct mp4 *f, uint32_t *result)
94 {
95         uint8_t data[4];
96         int ret = read_data(f, data, 4);
97
98         if (ret > 0 && result)
99                 *result = read_u32_be(data);
100         return ret;
101 }
102
103 static int read_int24(struct mp4 *f, uint32_t *result)
104 {
105         uint8_t data[3];
106         int ret = read_data(f, data, 3);
107
108         if (ret > 0 && result)
109                 *result = read_u24_be(data);
110         return ret;
111 }
112
113 static int read_int16(struct mp4 *f, uint16_t *result)
114 {
115         uint8_t data[2];
116         int ret = read_data(f, data, 2);
117
118         if (ret > 0 && result)
119                 *result = read_u16_be(data);
120         return ret;
121 }
122
123 static uint8_t read_int8(struct mp4 *f, uint8_t *result)
124 {
125         uint8_t data[1];
126         int ret = read_data(f, data, 1);
127
128         if (ret > 0 && result)
129                 *result = data[0];
130         return ret;
131 }
132
133 static bool atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
134                 int8_t a2, int8_t b2, int8_t c2, int8_t d2)
135 {
136         return a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2;
137 }
138
139 enum atoms {
140         /* atoms with subatoms */
141         ATOM_MOOV = 1,
142         ATOM_TRAK = 2,
143         ATOM_EDTS = 3,
144         ATOM_MDIA = 4,
145         ATOM_MINF = 5,
146         ATOM_STBL = 6,
147         ATOM_UDTA = 7,
148         ATOM_ILST = 8, /* iTunes Metadata list */
149         ATOM_TITLE = 9,
150         ATOM_ARTIST = 10,
151         ATOM_WRITER = 11,
152         ATOM_ALBUM = 12,
153         ATOM_DATE = 13,
154         ATOM_TOOL = 14,
155         ATOM_COMMENT = 15,
156         ATOM_GENRE1 = 16,
157         ATOM_TRACK = 17,
158         ATOM_DISC = 18,
159         ATOM_COMPILATION = 19,
160         ATOM_GENRE2 = 20,
161         ATOM_TEMPO = 21,
162         ATOM_COVER = 22,
163         ATOM_DRMS = 23,
164         ATOM_SINF = 24,
165         ATOM_SCHI = 25,
166
167         SUBATOMIC = 128,
168
169         /* atoms without subatoms */
170         ATOM_FTYP = 129,
171         ATOM_MDAT = 130,
172         ATOM_MVHD = 131,
173         ATOM_TKHD = 132,
174         ATOM_TREF = 133,
175         ATOM_MDHD = 134, /* track header */
176         ATOM_VMHD = 135,
177         ATOM_SMHD = 136,
178         ATOM_HMHD = 137,
179         ATOM_STSD = 138, /* sample description box */
180         ATOM_STTS = 139, /* time to sample box */
181         ATOM_STSZ = 140, /* sample size box */
182         ATOM_STZ2 = 141,
183         ATOM_STCO = 142, /* chunk offset box */
184         ATOM_STSC = 143, /* sample to chunk box */
185         ATOM_MP4A = 144,
186         ATOM_MP4V = 145,
187         ATOM_MP4S = 146,
188         ATOM_ESDS = 147,
189         ATOM_META = 148, /* iTunes Metadata box */
190         ATOM_NAME = 149, /* iTunes Metadata name box */
191         ATOM_DATA = 150, /* iTunes Metadata data box */
192         ATOM_CTTS = 151,
193         ATOM_FRMA = 152,
194         ATOM_IVIV = 153,
195         ATOM_PRIV = 154,
196         ATOM_USER = 155,
197         ATOM_KEY = 156,
198         ATOM_ALBUM_ARTIST = 157,
199         ATOM_CONTENTGROUP = 158,
200         ATOM_LYRICS = 159,
201         ATOM_DESCRIPTION = 160,
202         ATOM_NETWORK = 161,
203         ATOM_SHOW = 162,
204         ATOM_EPISODENAME = 163,
205         ATOM_SORTTITLE = 164,
206         ATOM_SORTALBUM = 165,
207         ATOM_SORTARTIST = 166,
208         ATOM_SORTALBUMARTIST = 167,
209         ATOM_SORTWRITER = 168,
210         ATOM_SORTSHOW = 169,
211         ATOM_SEASON = 170,
212         ATOM_EPISODE = 171,
213         ATOM_PODCAST = 172,
214
215         ATOM_UNKNOWN = 255
216 };
217
218 #define ATOM_FREE ATOM_UNKNOWN
219 #define ATOM_SKIP ATOM_UNKNOWN
220
221 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
222
223 static uint8_t atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
224 {
225         if (a == 'm') {
226                 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
227                         return ATOM_MOOV;
228                 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
229                         return ATOM_MINF;
230                 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
231                         return ATOM_MDIA;
232                 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
233                         return ATOM_MDAT;
234                 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
235                         return ATOM_MDHD;
236                 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
237                         return ATOM_MVHD;
238                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
239                         return ATOM_MP4A;
240                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
241                         return ATOM_MP4V;
242                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
243                         return ATOM_MP4S;
244                 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
245                         return ATOM_META;
246         } else if (a == 't') {
247                 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
248                         return ATOM_TRAK;
249                 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
250                         return ATOM_TKHD;
251                 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
252                         return ATOM_TREF;
253                 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
254                         return ATOM_TRACK;
255                 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
256                         return ATOM_TEMPO;
257                 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
258                         return ATOM_NETWORK;
259                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
260                         return ATOM_SHOW;
261                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
262                         return ATOM_EPISODENAME;
263                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
264                         return ATOM_SEASON;
265                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
266                         return ATOM_EPISODE;
267         } else if (a == 's') {
268                 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
269                         return ATOM_STBL;
270                 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
271                         return ATOM_SMHD;
272                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
273                         return ATOM_STSD;
274                 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
275                         return ATOM_STTS;
276                 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
277                         return ATOM_STCO;
278                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
279                         return ATOM_STSC;
280                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
281                         return ATOM_STSZ;
282                 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
283                         return ATOM_STZ2;
284                 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
285                         return ATOM_SKIP;
286                 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
287                         return ATOM_SINF;
288                 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
289                         return ATOM_SCHI;
290                 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
291                         return ATOM_SORTTITLE;
292                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
293                         return ATOM_SORTALBUM;
294                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
295                         return ATOM_SORTARTIST;
296                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
297                         return ATOM_SORTALBUMARTIST;
298                 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
299                         return ATOM_SORTWRITER;
300                 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
301                         return ATOM_SORTSHOW;
302         } else if (a == COPYRIGHT_SYMBOL) {
303                 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
304                         return ATOM_TITLE;
305                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
306                         return ATOM_ARTIST;
307                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
308                         return ATOM_WRITER;
309                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
310                         return ATOM_ALBUM;
311                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
312                         return ATOM_DATE;
313                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
314                         return ATOM_TOOL;
315                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
316                         return ATOM_COMMENT;
317                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
318                         return ATOM_GENRE1;
319                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
320                         return ATOM_CONTENTGROUP;
321                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
322                         return ATOM_LYRICS;
323         }
324
325         if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
326                 return ATOM_EDTS;
327         else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
328                 return ATOM_ESDS;
329         else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
330                 return ATOM_FTYP;
331         else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
332                 return ATOM_FREE;
333         else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
334                 return ATOM_HMHD;
335         else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
336                 return ATOM_VMHD;
337         else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
338                 return ATOM_UDTA;
339         else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
340                 return ATOM_ILST;
341         else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
342                 return ATOM_NAME;
343         else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
344                 return ATOM_DATA;
345         else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
346                 return ATOM_DISC;
347         else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
348                 return ATOM_GENRE2;
349         else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
350                 return ATOM_COVER;
351         else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
352                 return ATOM_COMPILATION;
353         else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
354                 return ATOM_CTTS;
355         else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
356                 return ATOM_DRMS;
357         else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
358                 return ATOM_FRMA;
359         else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
360                 return ATOM_PRIV;
361         else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
362                 return ATOM_IVIV;
363         else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
364                 return ATOM_USER;
365         else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
366                 return ATOM_KEY;
367         else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
368                 return ATOM_ALBUM_ARTIST;
369         else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
370                 return ATOM_DESCRIPTION;
371         else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
372                 return ATOM_PODCAST;
373         else
374                 return ATOM_UNKNOWN;
375 }
376
377 /* read atom header, atom size is returned with header included. */
378 static int atom_read_header(struct mp4 *f, uint8_t *atom_type,
379                 uint8_t *header_size, uint64_t *atom_size)
380 {
381         uint32_t size;
382         int ret;
383         int8_t atom_header[8];
384
385         ret = read_data(f, atom_header, 8);
386         if (ret <= 0)
387                 return ret;
388         size = read_u32_be(atom_header);
389         if (size == 1) { /* 64 bit atom size */
390                 if (header_size)
391                         *header_size = 16;
392                 ret = read_int64(f, atom_size);
393                 if (ret <= 0)
394                         return ret;
395         } else {
396                 if (header_size)
397                         *header_size = 8;
398                 if (atom_size)
399                         *atom_size = size;
400         }
401         *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
402                 atom_header[6], atom_header[7]);
403         return 1;
404 }
405
406 static int64_t get_position(const struct mp4 *f)
407 {
408         return f->current_position;
409 }
410
411 static int32_t set_position(struct mp4 *f, int64_t position)
412 {
413         f->cb->seek(f->cb->user_data, position);
414         f->current_position = position;
415
416         return 0;
417 }
418
419 static int read_stsz(struct mp4 *f)
420 {
421         int ret;
422         int32_t i;
423         struct mp4_track *t;
424
425         if (f->total_tracks == 0)
426                 return -1;
427         t = f->track[f->total_tracks - 1];
428         ret = read_int8(f, NULL); /* version */
429         if (ret <= 0)
430                 return ret;
431         ret = read_int24(f, NULL); /* flags */
432         if (ret <= 0)
433                 return ret;
434         ret = read_int32(f, &t->stsz_sample_size);
435         if (ret <= 0)
436                 return ret;
437         ret = read_int32(f, &t->stsz_sample_count);
438         if (ret <= 0)
439                 return ret;
440         if (t->stsz_sample_size != 0)
441                 return 1;
442         t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
443         for (i = 0; i < t->stsz_sample_count; i++) {
444                 ret = read_int32(f, &t->stsz_table[i]);
445                 if (ret <= 0)
446                         return ret;
447         }
448         return 1;
449 }
450
451 static int read_stts(struct mp4 *f)
452 {
453         int ret;
454         int32_t i;
455         struct mp4_track *t;
456
457         if (f->total_tracks == 0)
458                 return -1;
459         t = f->track[f->total_tracks - 1];
460         if (t->stts_entry_count)
461                 return 0;
462         ret = read_int8(f, NULL); /* version */
463         if (ret <= 0)
464                 return ret;
465         ret = read_int24(f, NULL); /* flags */
466         if (ret <= 0)
467                 return ret;
468         ret = read_int32(f, &t->stts_entry_count);
469         if (ret <= 0)
470                 return ret;
471         t->stts_sample_count = para_malloc(t->stts_entry_count
472                 * sizeof(int32_t));
473         for (i = 0; i < t->stts_entry_count; i++) {
474                 ret = read_int32(f, &t->stts_sample_count[i]);
475                 if (ret <= 0)
476                         return ret;
477                 ret = read_int32(f, NULL); /* sample delta */
478                 if (ret <= 0)
479                         return ret;
480         }
481         return 1;
482 }
483
484 static int read_stsc(struct mp4 *f)
485 {
486         int ret;
487         int32_t i;
488         struct mp4_track *t;
489
490         if (f->total_tracks == 0)
491                 return -1;
492         t = f->track[f->total_tracks - 1];
493
494         ret = read_int8(f, NULL); /* version */
495         if (ret <= 0)
496                 return ret;
497         ret = read_int24(f, NULL); /* flags */
498         if (ret <= 0)
499                 return ret;
500         ret = read_int32(f, &t->stsc_entry_count);
501         if (ret <= 0)
502                 return ret;
503         t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
504         t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
505                 * sizeof (int32_t));
506         for (i = 0; i < t->stsc_entry_count; i++) {
507                 ret = read_int32(f, &t->stsc_first_chunk[i]);
508                 if (ret <= 0)
509                         return ret;
510                 ret = read_int32(f, &t->stsc_samples_per_chunk[i]);
511                 if (ret <= 0)
512                         return ret;
513                 ret = read_int32(f, NULL); /* sample desc index */
514                 if (ret <= 0)
515                         return ret;
516         }
517         return 1;
518 }
519
520 static int read_stco(struct mp4 *f)
521 {
522         int ret;
523         int32_t i;
524         struct mp4_track *t;
525
526         if (f->total_tracks == 0)
527                 return -1;
528         t = f->track[f->total_tracks - 1];
529
530         ret = read_int8(f, NULL); /* version */
531         if (ret <= 0)
532                 return ret;
533         ret = read_int24(f, NULL); /* flags */
534         if (ret <= 0)
535                 return ret;
536         ret = read_int32(f, &t->stco_entry_count);
537         if (ret <= 0)
538                 return ret;
539         t->stco_chunk_offset = para_malloc(t->stco_entry_count
540                 * sizeof(int32_t));
541         for (i = 0; i < t->stco_entry_count; i++) {
542                 ret = read_int32(f, &t->stco_chunk_offset[i]);
543                 if (ret <= 0)
544                         return ret;
545         }
546         return 1;
547 }
548
549 static int read_mp4a(struct mp4 *f)
550 {
551         int ret;
552         int32_t i;
553         uint8_t atom_type = 0;
554         uint8_t header_size = 0;
555         struct mp4_track *t;
556
557         if (f->total_tracks == 0)
558                 return -1;
559         t = f->track[f->total_tracks - 1];
560
561         for (i = 0; i < 6; i++) {
562                 ret = read_int8(f, NULL); /* reserved */
563                 if (ret <= 0)
564                         return ret;
565         }
566         ret = read_int16(f, NULL); /* data_reference_index */
567         if (ret <= 0)
568                 return ret;
569         ret = read_int32(f, NULL); /* reserved */
570         if (ret <= 0)
571                 return ret;
572         ret = read_int32(f, NULL); /* reserved */
573         if (ret <= 0)
574                 return ret;
575         ret = read_int16(f, &t->channelCount);
576         if (ret <= 0)
577                 return ret;
578         ret = read_int16(f, NULL);
579         if (ret <= 0)
580                 return ret;
581         ret = read_int16(f, NULL);
582         if (ret <= 0)
583                 return ret;
584         ret = read_int16(f, NULL);
585         if (ret <= 0)
586                 return ret;
587         ret = read_int16(f, &t->sampleRate);
588         if (ret <= 0)
589                 return ret;
590         ret = read_int16(f, NULL);
591         if (ret <= 0)
592                 return ret;
593         return atom_read_header(f, &atom_type, &header_size, NULL);
594 }
595
596 static int read_stsd(struct mp4 *f)
597 {
598         int ret;
599         uint32_t i, entry_count;
600         uint8_t header_size = 0;
601         struct mp4_track *t;
602
603         if (f->total_tracks == 0)
604                 return -1;
605         t = f->track[f->total_tracks - 1];
606         ret = read_int8(f, NULL); /* version */
607         if (ret <= 0)
608                 return ret;
609         ret = read_int24(f, NULL); /* flags */
610         if (ret <= 0)
611                 return ret;
612         ret = read_int32(f, &entry_count);
613         if (ret <= 0)
614                 return ret;
615         for (i = 0; i < entry_count; i++) {
616                 uint64_t skip = get_position(f);
617                 uint64_t size;
618                 uint8_t atom_type = 0;
619                 ret = atom_read_header(f, &atom_type, &header_size, &size);
620                 if (ret <= 0)
621                         return ret;
622                 skip += size;
623                 if (!f->audio_track && atom_type == ATOM_MP4A) {
624                         f->audio_track = t;
625                         read_mp4a(f);
626                 }
627                 set_position(f, skip);
628         }
629         return 1;
630 }
631
632 static int32_t tag_add_field(struct mp4_metadata *meta, const char *item,
633                 const char *value, int32_t len)
634 {
635         meta->tags = para_realloc(meta->tags,
636                 (meta->count + 1) * sizeof(struct mp4_tag));
637         meta->tags[meta->count].item = para_strdup(item);
638         meta->tags[meta->count].len = len;
639         if (len >= 0) {
640                 meta->tags[meta->count].value = para_malloc(len + 1);
641                 memcpy(meta->tags[meta->count].value, value, len);
642                 meta->tags[meta->count].value[len] = 0;
643         } else {
644                 meta->tags[meta->count].value = para_strdup(value);
645         }
646         meta->count++;
647         return 1;
648 }
649
650 static int read_string(struct mp4 *f, uint32_t length, char **result)
651 {
652         char *str = para_malloc(length + 1);
653         int ret = read_data(f, str, length);
654
655         if (ret <= 0) {
656                 free(str);
657                 *result = NULL;
658         } else {
659                 str[length] = '\0';
660                 *result = str;
661         }
662         return ret;
663 }
664
665 static const char *get_metadata_name(uint8_t atom_type)
666 {
667         switch (atom_type) {
668         case ATOM_TITLE: return "title";
669         case ATOM_ARTIST: return "artist";
670         case ATOM_ALBUM: return "album";
671         case ATOM_DATE: return "date";
672         case ATOM_COMMENT: return "comment";
673         default: return "unknown";
674         }
675 }
676
677 static int parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
678 {
679         int ret;
680         uint64_t subsize, sumsize;
681         char *data = NULL;
682         uint32_t len = 0;
683         uint64_t destpos;
684
685         for (
686                 sumsize = 0;
687                 sumsize < size;
688                 set_position(f, destpos), sumsize += subsize
689         ) {
690                 uint8_t atom_type;
691                 uint8_t header_size = 0;
692                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
693                 if (ret <= 0)
694                         return ret;
695                 destpos = get_position(f) + subsize - header_size;
696                 if (atom_type != ATOM_DATA)
697                         continue;
698                 ret = read_int8(f, NULL); /* version */
699                 if (ret <= 0)
700                         return ret;
701                 ret = read_int24(f, NULL); /* flags */
702                 if (ret <= 0)
703                         return ret;
704                 ret = read_int32(f, NULL); /* reserved */
705                 if (ret <= 0)
706                         return ret;
707                 free(data);
708                 ret = read_string(f, subsize - (header_size + 8), &data);
709                 if (ret <= 0)
710                         return ret;
711                 len = subsize - (header_size + 8);
712         }
713         if (!data)
714                 return -1;
715         tag_add_field(&f->meta, get_metadata_name(parent), data, len);
716         free(data);
717         return 1;
718 }
719
720 static int read_mdhd(struct mp4 *f)
721 {
722         int ret;
723         uint32_t version;
724         struct mp4_track *t;
725
726         if (f->total_tracks == 0)
727                 return -1;
728         t = f->track[f->total_tracks - 1];
729
730         ret = read_int32(f, &version);
731         if (ret <= 0)
732                 return ret;
733         if (version == 1) {
734                 ret = read_int64(f, NULL); /* creation-time */
735                 if (ret <= 0)
736                         return ret;
737                 ret = read_int64(f, NULL); /* modification-time */
738                 if (ret <= 0)
739                         return ret;
740                 ret = read_int32(f, &t->timeScale);
741                 if (ret <= 0)
742                         return ret;
743                 ret = read_int64(f, &t->duration);
744                 if (ret <= 0)
745                         return ret;
746         } else { //version == 0
747                 uint32_t temp;
748
749                 ret = read_int32(f, NULL); /* creation-time */
750                 if (ret <= 0)
751                         return ret;
752                 ret = read_int32(f, NULL); /* modification-time */
753                 if (ret <= 0)
754                         return ret;
755                 ret = read_int32(f, &t->timeScale);
756                 if (ret <= 0)
757                         return ret;
758                 ret = read_int32(f, &temp);
759                 if (ret <= 0)
760                         return ret;
761                 t->duration = (temp == (uint32_t) (-1))?
762                         (uint64_t) (-1) : (uint64_t) (temp);
763         }
764         ret = read_int16(f, NULL);
765         if (ret <= 0)
766                 return ret;
767         ret = read_int16(f, NULL);
768         if (ret <= 0)
769                 return ret;
770         return 1;
771 }
772
773 static int32_t read_ilst(struct mp4 *f, int32_t size)
774 {
775         int ret;
776         uint64_t sumsize = 0;
777
778         while (sumsize < size) {
779                 uint8_t atom_type;
780                 uint64_t subsize, destpos;
781                 uint8_t header_size = 0;
782                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
783                 if (ret <= 0)
784                         return ret;
785                 destpos = get_position(f) + subsize - header_size;
786                 switch (atom_type) {
787                 case ATOM_ARTIST:
788                 case ATOM_TITLE:
789                 case ATOM_ALBUM:
790                 case ATOM_COMMENT:
791                 case ATOM_DATE:
792                         parse_tag(f, atom_type, subsize - header_size);
793                 }
794                 set_position(f, destpos);
795                 sumsize += subsize;
796         }
797         return 1;
798 }
799
800 static int32_t read_meta(struct mp4 *f, uint64_t size)
801 {
802         int ret;
803         uint64_t subsize, sumsize = 0;
804         uint8_t atom_type;
805         uint8_t header_size = 0;
806
807         ret = read_int8(f, NULL); /* version */
808         if (ret <= 0)
809                 return ret;
810         ret = read_int24(f, NULL); /* flags */
811         if (ret <= 0)
812                 return ret;
813         while (sumsize < (size - (header_size + 4))) {
814                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
815                 if (ret <= 0)
816                         return ret;
817                 if (subsize <= header_size + 4)
818                         return 1;
819                 if (atom_type == ATOM_ILST)
820                         read_ilst(f, subsize - (header_size + 4));
821                 else
822                         set_position(f, get_position(f) + subsize - header_size);
823                 sumsize += subsize;
824         }
825         return 1;
826 }
827
828 static int parse_leaf_atom(struct mp4 *f, uint64_t size, uint8_t atom_type)
829 {
830         uint64_t dest_position = get_position(f) + size - 8;
831         int ret = 1; /* return success for atoms we don't care about */
832
833         switch (atom_type) {
834         case ATOM_STSZ: ret = read_stsz(f); break;
835         case ATOM_STTS: ret = read_stts(f); break;
836         case ATOM_STSC: ret = read_stsc(f); break;
837         case ATOM_STCO: ret = read_stco(f); break;
838         case ATOM_STSD: ret = read_stsd(f); break;
839         case ATOM_MDHD: ret = read_mdhd(f); break;
840         case ATOM_META: ret = read_meta(f, size); break;
841         }
842         set_position(f, dest_position);
843         return ret;
844 }
845
846 static bool need_atom(uint8_t atom_type, bool meta_only)
847 {
848         /* these are needed in any case */
849         switch (atom_type) {
850         case ATOM_STSD:
851         case ATOM_META:
852         case ATOM_TRAK:
853         case ATOM_MDIA:
854         case ATOM_MINF:
855         case ATOM_STBL:
856                 return true;
857         }
858         /* meta-only opens don't need anything else */
859         if (meta_only)
860                 return false;
861         /* these are only required for regular opens */
862         switch (atom_type) {
863         case ATOM_STTS:
864         case ATOM_STSZ:
865         case ATOM_STCO:
866         case ATOM_STSC:
867         case ATOM_MDHD:
868         case ATOM_UDTA:
869                 return true;
870         }
871         return false;
872 }
873
874 /* parse atoms that are sub atoms of other atoms */
875 static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, bool meta_only)
876 {
877         int ret;
878         uint64_t size;
879         uint8_t atom_type = 0;
880         uint64_t counted_size = 0;
881         uint8_t header_size = 0;
882
883         while (counted_size < total_size) {
884                 ret = atom_read_header(f, &atom_type, &header_size, &size);
885                 if (ret <= 0)
886                         return ret;
887                 if (size == 0)
888                         return -1;
889                 counted_size += size;
890                 if (atom_type == ATOM_TRAK) {
891                         if (f->total_tracks >= MAX_TRACKS)
892                                 return -1;
893                         f->total_tracks++;
894                         f->track[f->total_tracks - 1] = para_calloc(
895                                 sizeof(struct mp4_track));
896                 }
897                 if (!need_atom(atom_type, meta_only)) {
898                         set_position(f, get_position(f) + size - header_size);
899                         continue;
900                 }
901                 if (atom_type < SUBATOMIC) /* atom contains subatoms */
902                         ret = parse_sub_atoms(f, size - header_size, meta_only);
903                 else
904                         ret = parse_leaf_atom(f, size, atom_type);
905                 if (ret <= 0)
906                         return ret;
907         }
908         return 1;
909 }
910
911 static int parse_root_atoms(struct mp4 *f, bool meta_only)
912 {
913         int ret;
914         uint64_t size;
915         uint8_t atom_type = 0;
916         uint8_t header_size = 0;
917
918         f->file_size = 0;
919
920         while ((ret = atom_read_header(f, &atom_type, &header_size, &size)) > 0) {
921                 f->file_size += size;
922                 f->last_atom = atom_type;
923                 if (atom_type != ATOM_MOOV || size <= header_size) { /* skip */
924                         set_position(f, get_position(f) + size - header_size);
925                         continue;
926                 }
927                 f->moov_offset = get_position(f) - header_size;
928                 f->moov_size = size;
929                 ret = parse_sub_atoms(f, size - header_size, meta_only);
930                 if (ret <= 0)
931                         break;
932         }
933         if (ret < 0)
934                 return ret;
935         if (!f->audio_track)
936                 return -E_MP4_TRACK;
937         return ret;
938 }
939
940 struct mp4 *mp4_open_read(const struct mp4_callback *cb)
941 {
942         int ret;
943         struct mp4 *f = para_calloc(sizeof(struct mp4));
944
945         f->cb = cb;
946         ret = parse_root_atoms(f, false);
947         if (ret < 0) {
948                 free(f);
949                 return NULL;
950         }
951         return f;
952 }
953
954 void mp4_close(struct mp4 *f)
955 {
956         int32_t i;
957
958         for (i = 0; i < f->total_tracks; i++) {
959                 if (f->track[i]) {
960                         free(f->track[i]->stsz_table);
961                         free(f->track[i]->stts_sample_count);
962                         free(f->track[i]->stsc_first_chunk);
963                         free(f->track[i]->stsc_samples_per_chunk);
964                         free(f->track[i]->stco_chunk_offset);
965                         free(f->track[i]);
966                 }
967         }
968         for (i = 0; i < f->meta.count; i++) {
969                 free(f->meta.tags[i].item);
970                 free(f->meta.tags[i].value);
971         }
972         free(f->meta.tags);
973         free(f);
974 }
975
976 static int32_t chunk_of_sample(const struct mp4 *f, int32_t sample,
977                 int32_t *chunk)
978 {
979         const struct mp4_track *t = f->audio_track;
980         uint32_t *fc = t->stsc_first_chunk, *spc = t->stsc_samples_per_chunk;
981         int32_t chunk1, chunk1samples, n, total, i;
982
983         for (i = 1, total = 0; i < t->stsc_entry_count; i++, total += n) {
984                 n = (fc[i] - fc[i - 1]) * spc[i - 1]; /* number of samples */
985                 if (sample < total + n)
986                         break;
987         }
988         chunk1 = fc[i - 1];
989         chunk1samples = spc[i - 1];
990         if (chunk1samples != 0)
991                 *chunk = (sample - total) / chunk1samples + chunk1;
992         else
993                 *chunk = 1;
994         return total + (*chunk - chunk1) * chunk1samples;
995 }
996
997 /**
998  * Return the number of milliseconds of the audio track.
999  *
1000  * \param f As returned by \ref mp4_open_read(), must not be NULL.
1001  */
1002 uint64_t mp4_get_duration(const struct mp4 *f)
1003 {
1004         const struct mp4_track *t = f->audio_track;
1005
1006         if (t->timeScale == 0)
1007                 return 0;
1008         return t->duration * 1000 / t->timeScale;
1009 }
1010
1011 int mp4_set_sample_position(struct mp4 *f, int32_t sample)
1012 {
1013         const struct mp4_track *t = f->audio_track;
1014         int32_t offset, chunk, chunk_sample;
1015         uint32_t n, srs; /* sample range size */
1016
1017         if (sample >= t->stsz_sample_count)
1018                 return -ERRNO_TO_PARA_ERROR(EINVAL);
1019         chunk_sample = chunk_of_sample(f, sample, &chunk);
1020         if (t->stsz_sample_size > 0)
1021                 srs = (sample - chunk_sample) * t->stsz_sample_size;
1022         else {
1023                 for (srs = 0, n = chunk_sample; n < sample; n++)
1024                         srs += t->stsz_table[n];
1025         }
1026         if (t->stco_entry_count > 0 && chunk > t->stco_entry_count)
1027                 offset = t->stco_chunk_offset[t->stco_entry_count - 1];
1028         else if (t->stco_entry_count > 0)
1029                 offset = t->stco_chunk_offset[chunk - 1];
1030         else
1031                 offset = 8;
1032         set_position(f, offset + srs);
1033         return 1;
1034 }
1035
1036 int32_t mp4_get_sample_size(const struct mp4 *f, int sample)
1037 {
1038         const struct mp4_track *t = f->audio_track;
1039
1040         if (t->stsz_sample_size != 0)
1041                 return t->stsz_sample_size;
1042         return t->stsz_table[sample];
1043 }
1044
1045 uint32_t mp4_get_sample_rate(const struct mp4 *f)
1046 {
1047         return f->audio_track->sampleRate;
1048 }
1049
1050 uint32_t mp4_get_channel_count(const struct mp4 *f)
1051 {
1052         return f->audio_track->channelCount ;
1053 }
1054
1055 int32_t mp4_num_samples(const struct mp4 *f)
1056 {
1057         const struct mp4_track *t = f->audio_track;
1058         int32_t i;
1059         int32_t total = 0;
1060
1061         for (i = 0; i < t->stts_entry_count; i++)
1062                 total += t->stts_sample_count[i];
1063         return total;
1064 }
1065
1066 struct mp4 *mp4_open_meta(const struct mp4_callback *cb)
1067 {
1068         int ret;
1069         struct mp4 *f = para_calloc(sizeof(struct mp4));
1070
1071         f->cb = cb;
1072         ret = parse_root_atoms(f, true);
1073         if (ret < 0) {
1074                 free(f);
1075                 return NULL;
1076         }
1077         return f;
1078 }
1079
1080 /**
1081  * Return the metadata of an mp4 file.
1082  *
1083  * \param f As returned by either \ref mp4_open_read() or \ref mp4_open_meta().
1084  *
1085  * The caller is allowed to add, delete or modify the entries of the returned
1086  * structure in order to pass the modified version to \ref mp4_meta_update().
1087  */
1088 struct mp4_metadata *mp4_get_meta(struct mp4 *f)
1089 {
1090         return &f->meta;
1091 }
1092
1093 static int find_atom(struct mp4 *f, uint64_t base, uint32_t size,
1094         const char *name)
1095 {
1096         uint32_t remaining = size;
1097         uint64_t atom_offset = base;
1098
1099         for (;;) {
1100                 int ret;
1101                 char atom_name[4];
1102                 uint32_t atom_size;
1103
1104                 set_position(f, atom_offset);
1105
1106                 if (remaining < 8)
1107                         return -1;
1108                 ret = read_int32(f, &atom_size);
1109                 if (ret <= 0)
1110                         return ret;
1111                 if (atom_size > remaining || atom_size < 8)
1112                         return -1;
1113                 ret = read_data(f, atom_name, 4);
1114                 if (ret <= 0)
1115                         return ret;
1116                 if (!memcmp(atom_name, name, 4)) {
1117                         set_position(f, atom_offset);
1118                         return 1;
1119                 }
1120                 remaining -= atom_size;
1121                 atom_offset += atom_size;
1122         }
1123 }
1124
1125 /*
1126  * Try to find atom <name> with atom <name_inside> in it. Besides -1/0/1 for
1127  * error, EOF and success, this function may return 2 to indicate that the
1128  * desired atoms were not found.
1129  */
1130 static int find_atom_v2(struct mp4 *f, uint64_t base, uint32_t size,
1131                 const char *name, uint32_t extraheaders, const char *name_inside)
1132 {
1133         uint64_t first_base = (uint64_t) (-1);
1134
1135         for (;;) {
1136                 uint64_t mybase;
1137                 uint32_t mysize;
1138                 int ret = find_atom(f, base, size, name);
1139
1140                 if (ret <= 0)
1141                         return ret;
1142                 mybase = get_position(f);
1143                 ret = read_int32(f, &mysize);
1144                 if (ret <= 0)
1145                         return ret;
1146                 if (first_base == (uint64_t) (-1))
1147                         first_base = mybase;
1148
1149                 if (mysize < 8 + extraheaders)
1150                         break;
1151
1152                 if (find_atom (f, mybase + (8 + extraheaders),
1153                                 mysize - (8 + extraheaders), name_inside)) {
1154                         set_position(f, mybase);
1155                         return 1;
1156                 }
1157                 base += mysize;
1158                 if (size <= mysize)
1159                         break;
1160                 size -= mysize;
1161         }
1162         if (first_base != (uint64_t)(-1)) {
1163                 set_position(f, first_base);
1164                 return 1;
1165         }
1166         /* wanted atom inside not found */
1167         return 2;
1168 }
1169
1170 struct membuffer {
1171         void *data;
1172         unsigned written;
1173         unsigned allocated;
1174 };
1175
1176 static struct membuffer *membuffer_create(void)
1177 {
1178         struct membuffer *buf = para_calloc(sizeof(*buf));
1179
1180         buf->allocated = 256;
1181         buf->data = para_malloc(buf->allocated);
1182         return buf;
1183 }
1184
1185 static void membuffer_write(struct membuffer *buf, const void *ptr,
1186                 unsigned bytes)
1187 {
1188         unsigned dest_size = buf->written + bytes;
1189
1190         if (dest_size > buf->allocated) {
1191                 do {
1192                         buf->allocated <<= 1;
1193                 } while (dest_size > buf->allocated);
1194                 buf->data = para_realloc(buf->data, buf->allocated);
1195         }
1196
1197         if (ptr)
1198                 memcpy((char *) buf->data + buf->written, ptr, bytes);
1199         buf->written += bytes;
1200 }
1201
1202 static void membuffer_write_atom_name(struct membuffer *buf, const char *data)
1203 {
1204         membuffer_write(buf, data, 4);
1205 }
1206
1207 static void membuffer_write_int32(struct membuffer *buf, uint32_t data)
1208 {
1209         uint8_t temp[4];
1210         write_u32_be(temp, data);
1211         membuffer_write(buf, temp, 4);
1212 }
1213
1214 static void membuffer_write_std_tag(struct membuffer *buf, const char *name,
1215                 const char *value)
1216 {
1217         uint32_t len = strlen(value);
1218         membuffer_write_int32(buf, 8 /* atom header */
1219                 + 8 /* data atom header */
1220                 + 8 /* flags + reserved */
1221                 + len);
1222         membuffer_write_atom_name(buf, name);
1223         membuffer_write_int32(buf, 8 /* data atom header */
1224                 + 8 /* flags + reserved */
1225                 + len);
1226         membuffer_write_atom_name(buf, "data");
1227         membuffer_write_int32(buf, 1);  /* flags */
1228         membuffer_write_int32(buf, 0);  /* reserved */
1229         membuffer_write(buf, value, len);
1230 }
1231
1232 static unsigned membuffer_get_size(const struct membuffer *buf)
1233 {
1234         return buf->written;
1235 }
1236
1237 static void *membuffer_detach(struct membuffer *buf)
1238 {
1239         void *ret = para_realloc(buf->data, buf->written);
1240         free(buf);
1241         return ret;
1242 }
1243
1244 struct stdmeta_entry {
1245         const char *atom;
1246         const char *name;
1247 };
1248
1249 static const char *find_standard_meta(const char *name)
1250 {
1251         const struct stdmeta_entry stdmetas[] = {
1252                 {"\xA9" "nam", "title"},
1253                 {"\xA9" "ART", "artist"},
1254                 {"\xA9" "alb", "album"},
1255                 {"\xA9" "day", "date"},
1256                 {"\xA9" "cmt", "comment"},
1257         };
1258
1259         for (unsigned n = 0; n < ARRAY_SIZE(stdmetas); n++)
1260                 if (!strcasecmp(name, stdmetas[n].name))
1261                         return stdmetas[n].atom;
1262         return NULL;
1263 }
1264
1265 static uint32_t create_ilst(const struct mp4_metadata *meta, void **out_buffer,
1266                 uint32_t * out_size)
1267 {
1268         struct membuffer *buf = membuffer_create();
1269         unsigned metaptr;
1270
1271         for (metaptr = 0; metaptr < meta->count; metaptr++) {
1272                 struct mp4_tag *tag = meta->tags + metaptr;
1273                 const char *std_meta_atom = find_standard_meta(tag->item);
1274                 if (std_meta_atom)
1275                         membuffer_write_std_tag(buf, std_meta_atom, tag->value);
1276                 else
1277                         PARA_ERROR_LOG("invalid tag item: %s\n", tag->item);
1278         }
1279         *out_size = membuffer_get_size(buf);
1280         *out_buffer = membuffer_detach(buf);
1281         return 1;
1282 }
1283
1284 static void membuffer_write_atom(struct membuffer *buf, const char *name, unsigned size,
1285                           const void *data)
1286 {
1287         membuffer_write_int32(buf, size + 8);
1288         membuffer_write_atom_name(buf, name);
1289         membuffer_write(buf, data, size);
1290 }
1291
1292 static void *membuffer_get_ptr(const struct membuffer *buf)
1293 {
1294         return buf->data;
1295 }
1296
1297 static bool membuffer_transfer_from_file(struct membuffer *buf, struct mp4 *src,
1298                 unsigned bytes)
1299 {
1300         unsigned oldsize = membuffer_get_size(buf);
1301         char *bufptr;
1302
1303         membuffer_write(buf, 0, bytes);
1304         bufptr = membuffer_get_ptr(buf);
1305         if (read_data(src, bufptr + oldsize, bytes) != 1) {
1306                 free(buf->data);
1307                 free(buf);
1308                 return false;
1309         }
1310         return true;
1311 }
1312
1313 static uint32_t create_meta(const struct mp4_metadata *meta, void **out_buffer,
1314                 uint32_t * out_size)
1315 {
1316         struct membuffer *buf;
1317         uint32_t ilst_size;
1318         void *ilst_buffer;
1319
1320         if (!create_ilst(meta, &ilst_buffer, &ilst_size))
1321                 return 0;
1322
1323         buf = membuffer_create();
1324
1325         membuffer_write_int32(buf, 0);
1326         membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1327         free(ilst_buffer);
1328
1329         *out_size = membuffer_get_size(buf);
1330         *out_buffer = membuffer_detach(buf);
1331         return 1;
1332 }
1333
1334 static uint32_t create_udta(const struct mp4_metadata *meta, void **out_buffer,
1335 uint32_t * out_size)
1336 {
1337         struct membuffer *buf;
1338         uint32_t meta_size;
1339         void *meta_buffer;
1340
1341         if (!create_meta(meta, &meta_buffer, &meta_size))
1342                 return 0;
1343
1344         buf = membuffer_create();
1345
1346         membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1347
1348         free(meta_buffer);
1349
1350         *out_size = membuffer_get_size(buf);
1351         *out_buffer = membuffer_detach(buf);
1352         return 1;
1353 }
1354
1355 static uint32_t fix_byte_order_32(uint32_t src)
1356 {
1357         return read_u32_be(&src);
1358 }
1359
1360 static void *modify_moov(struct mp4 *f, uint32_t *out_size)
1361 {
1362         int ret;
1363         uint64_t total_base = f->moov_offset + 8;
1364         uint32_t total_size = (uint32_t) (f->moov_size - 8);
1365         uint64_t udta_offset, meta_offset, ilst_offset;
1366         uint32_t udta_size, meta_size, ilst_size;
1367         uint32_t new_ilst_size;
1368         void *new_ilst_buffer, *out_buffer;
1369         uint8_t *p_out;
1370         int32_t size_delta;
1371         uint32_t tmp;
1372
1373         ret = find_atom_v2(f, total_base, total_size, "udta", 0, "meta");
1374         if (ret <= 0)
1375                 return NULL;
1376         if (ret == 2) {
1377                 struct membuffer *buf;
1378                 void *new_udta_buffer;
1379                 uint32_t new_udta_size;
1380                 if (!create_udta(&f->meta, &new_udta_buffer, &new_udta_size))
1381                         return NULL;
1382
1383                 buf = membuffer_create();
1384                 set_position(f, total_base);
1385                 if (!membuffer_transfer_from_file(buf, f, total_size)) {
1386                         free(new_udta_buffer);
1387                         return NULL;
1388                 }
1389                 membuffer_write_atom(buf, "udta", new_udta_size,
1390                         new_udta_buffer);
1391
1392                 free(new_udta_buffer);
1393
1394                 *out_size = membuffer_get_size(buf);
1395                 return membuffer_detach(buf);
1396         }
1397         udta_offset = get_position(f);
1398         ret = read_int32(f, &udta_size);
1399         if (ret <= 0)
1400                 return NULL;
1401         ret = find_atom_v2(f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst");
1402         if (ret <= 0)
1403                 return NULL;
1404         if (ret == 2) {
1405                 struct membuffer *buf;
1406                 void *new_meta_buffer;
1407                 uint32_t new_meta_size;
1408
1409                 if (!create_meta(&f->meta, &new_meta_buffer, &new_meta_size))
1410                         return NULL;
1411
1412                 buf = membuffer_create();
1413                 set_position(f, total_base);
1414                 if (!membuffer_transfer_from_file(buf, f,
1415                                 udta_offset - total_base)) {
1416                         free(new_meta_buffer);
1417                         return NULL;
1418                 }
1419
1420                 membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
1421                 membuffer_write_atom_name(buf, "udta");
1422                 if (!membuffer_transfer_from_file(buf, f, udta_size)) {
1423                         free(new_meta_buffer);
1424                         return NULL;
1425                 }
1426                 membuffer_write_atom(buf, "meta", new_meta_size,
1427                         new_meta_buffer);
1428                 free(new_meta_buffer);
1429
1430                 *out_size = membuffer_get_size(buf);
1431                 return membuffer_detach(buf);
1432         }
1433         meta_offset = get_position(f);
1434         ret = read_int32(f, &meta_size);
1435         if (ret <= 0)
1436                 return NULL;
1437         /* shouldn't happen, find_atom_v2 above takes care of it */
1438         if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
1439                 return NULL;
1440         ilst_offset = get_position(f);
1441         ret = read_int32(f, &ilst_size);
1442         if (ret <= 0)
1443                 return NULL;
1444         if (!create_ilst(&f->meta, &new_ilst_buffer, &new_ilst_size))
1445                 return NULL;
1446         size_delta = new_ilst_size - (ilst_size - 8);
1447         *out_size = total_size + size_delta;
1448         out_buffer = para_malloc(*out_size);
1449         p_out = out_buffer;
1450         set_position(f, total_base);
1451         ret = read_data(f, p_out, udta_offset - total_base);
1452         if (ret <= 0)
1453                 return NULL;
1454         p_out += (uint32_t) (udta_offset - total_base);
1455         ret = read_int32(f, &tmp);
1456         if (ret <= 0)
1457                 return NULL;
1458         *(uint32_t *)p_out = fix_byte_order_32(tmp + size_delta);
1459         p_out += 4;
1460         ret = read_data(f, p_out, 4);
1461         if (ret <= 0)
1462                 return NULL;
1463         p_out += 4;
1464         ret = read_data(f, p_out, meta_offset - udta_offset - 8);
1465         if (ret <= 0)
1466                 return NULL;
1467         p_out += (uint32_t) (meta_offset - udta_offset - 8);
1468         ret = read_int32(f, &tmp);
1469         if (ret <= 0)
1470                 return NULL;
1471         *(uint32_t *)p_out = fix_byte_order_32(tmp + size_delta);
1472         p_out += 4;
1473         ret = read_data(f, p_out, 4);
1474         if (ret <= 0)
1475                 return NULL;
1476         p_out += 4;
1477         ret = read_data(f, p_out, ilst_offset - meta_offset - 8);
1478         if (ret <= 0)
1479                 return NULL;
1480         p_out += (uint32_t) (ilst_offset - meta_offset - 8);
1481         ret = read_int32(f, &tmp);
1482         if (ret <= 0)
1483                 return NULL;
1484         *(uint32_t *)p_out = fix_byte_order_32(tmp + size_delta);
1485         p_out += 4;
1486         ret = read_data(f, p_out, 4);
1487         if (ret <= 0)
1488                 return NULL;
1489         p_out += 4;
1490         memcpy(p_out, new_ilst_buffer, new_ilst_size);
1491         p_out += new_ilst_size;
1492         set_position(f, ilst_offset + ilst_size);
1493         ret = read_data(f, p_out, total_size
1494                 - (ilst_offset - total_base) - ilst_size);
1495         if (ret <= 0)
1496                 return NULL;
1497         free(new_ilst_buffer);
1498         return out_buffer;
1499 }
1500
1501 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
1502 {
1503         int32_t result = 1;
1504
1505         result = f->cb->write(f->cb->user_data, data, size);
1506
1507         f->current_position += size;
1508
1509         return result;
1510 }
1511
1512 static int32_t write_int32(struct mp4 *f, uint32_t data)
1513 {
1514         int8_t temp[4];
1515         write_u32_be(temp, data);
1516         return write_data(f, temp, sizeof(temp));
1517 }
1518
1519 int32_t mp4_meta_update(struct mp4 *f)
1520 {
1521         void *new_moov_data;
1522         uint32_t new_moov_size;
1523
1524         set_position(f, 0);
1525         new_moov_data = modify_moov(f, &new_moov_size);
1526         if (!new_moov_data ) {
1527                 mp4_close(f);
1528                 return 0;
1529         }
1530         /* copy moov atom to end of the file */
1531         if (f->last_atom != ATOM_MOOV) {
1532                 char *free_data = "free";
1533
1534                 /* rename old moov to free */
1535                 set_position(f, f->moov_offset + 4);
1536                 write_data(f, free_data, 4);
1537
1538                 set_position(f, f->file_size);
1539                 write_int32(f, new_moov_size + 8);
1540                 write_data(f, "moov", 4);
1541                 write_data(f, new_moov_data, new_moov_size);
1542         } else {
1543                 set_position(f, f->moov_offset);
1544                 write_int32(f, new_moov_size + 8);
1545                 write_data(f, "moov", 4);
1546                 write_data(f, new_moov_data, new_moov_size);
1547         }
1548         free(new_moov_data);
1549         f->cb->truncate(f->cb->user_data);
1550         return 1;
1551 }
1552
1553 static char *meta_find_by_name(const struct mp4 *f, const char *item)
1554 {
1555         uint32_t i;
1556
1557         for (i = 0; i < f->meta.count; i++)
1558                 if (!strcasecmp(f->meta.tags[i].item, item))
1559                         return para_strdup(f->meta.tags[i].value);
1560         return NULL;
1561 }
1562
1563 /**
1564  * Return the value of the artist meta tag of an mp4 file.
1565  *
1566  * \param f Must not be NULL.
1567  *
1568  * \return If the file does not contain this metadata tag, the function returns
1569  * NULL. Otherwise, a copy of the tag value is returned. The caller should free
1570  * this memory when it is no longer needed.
1571  */
1572 char *mp4_meta_get_artist(const struct mp4 *f)
1573 {
1574         return meta_find_by_name(f, "artist");
1575 }
1576
1577 /**
1578  * Return the value of the title meta tag of an mp4 file.
1579  *
1580  * \param f See \ref mp4_meta_get_artist().
1581  * \return See \ref mp4_meta_get_artist().
1582  */
1583 char *mp4_meta_get_title(const struct mp4 *f)
1584 {
1585         return meta_find_by_name(f, "title");
1586 }
1587
1588 /**
1589  * Return the value of the date meta tag of an mp4 file.
1590  *
1591  * \param f See \ref mp4_meta_get_artist().
1592  * \return See \ref mp4_meta_get_artist().
1593  */
1594 char *mp4_meta_get_date(const struct mp4 *f)
1595 {
1596         return meta_find_by_name(f, "date");
1597 }
1598
1599 /**
1600  * Return the value of the album meta tag of an mp4 file.
1601  *
1602  * \param f See \ref mp4_meta_get_artist().
1603  * \return See \ref mp4_meta_get_artist().
1604  */
1605 char *mp4_meta_get_album(const struct mp4 *f)
1606 {
1607         return meta_find_by_name(f, "album");
1608 }
1609
1610 /**
1611  * Return the value of the comment meta tag of an mp4 file.
1612  *
1613  * \param f See \ref mp4_meta_get_artist().
1614  * \return See \ref mp4_meta_get_artist().
1615  */
1616 char *mp4_meta_get_comment(const struct mp4 *f)
1617 {
1618         return meta_find_by_name(f, "comment");
1619 }