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