]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
d73165a3715f088177a437d6c032aa525bbe5bec
[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         uint64_t meta_offset;
51         uint32_t meta_size;
52         uint64_t ilst_offset;
53         uint32_t ilst_size;
54         uint64_t udta_offset;
55         uint32_t udta_size;
56
57         uint8_t last_atom;
58         uint64_t file_size;
59
60         /* incremental track index while reading the file */
61         int32_t total_tracks;
62         /* track data */
63         struct mp4_track *track[MAX_TRACKS];
64         /* the first audio track found */
65         struct mp4_track *audio_track;
66
67         /* metadata */
68         struct mp4_metadata meta;
69 };
70
71 /*
72  * Returns -1, 0, or 1 on errors/EOF/success. Partial reads followed by EOF or
73  * read errors are treated as errors.
74  */
75 static int read_data(struct mp4 *f, void *data, size_t size)
76 {
77         while (size > 0) {
78                 ssize_t ret = f->cb->read(f->cb->user_data, data, size);
79                 if (ret < 0 && errno == EINTR)
80                         continue;
81                 /* regard EAGAIN as an error as reads should be blocking. */
82                 if (ret <= 0)
83                         return ret < 0? -1 : 0;
84                 f->current_position += ret;
85                 size -= ret;
86         }
87         return 1;
88 }
89
90 static int read_int64(struct mp4 *f, uint64_t *result)
91 {
92         uint8_t data[8];
93         int ret = read_data(f, data, 8);
94
95         if (ret > 0 && result)
96                 *result = read_u64_be(data);
97         return ret;
98 }
99
100 static int read_int32(struct mp4 *f, uint32_t *result)
101 {
102         uint8_t data[4];
103         int ret = read_data(f, data, 4);
104
105         if (ret > 0 && result)
106                 *result = read_u32_be(data);
107         return ret;
108 }
109
110 static int read_int24(struct mp4 *f, uint32_t *result)
111 {
112         uint8_t data[3];
113         int ret = read_data(f, data, 3);
114
115         if (ret > 0 && result)
116                 *result = read_u24_be(data);
117         return ret;
118 }
119
120 static int read_int16(struct mp4 *f, uint16_t *result)
121 {
122         uint8_t data[2];
123         int ret = read_data(f, data, 2);
124
125         if (ret > 0 && result)
126                 *result = read_u16_be(data);
127         return ret;
128 }
129
130 static uint8_t read_int8(struct mp4 *f, uint8_t *result)
131 {
132         uint8_t data[1];
133         int ret = read_data(f, data, 1);
134
135         if (ret > 0 && result)
136                 *result = data[0];
137         return ret;
138 }
139
140 #define ATOM_ITEMS \
141         ATOM_ITEM(MOOV, 'm', 'o', 'o', 'v') \
142         ATOM_ITEM(TRAK, 't', 'r', 'a', 'k') \
143         ATOM_ITEM(MDIA, 'm', 'd', 'i', 'a') \
144         ATOM_ITEM(MINF, 'm', 'i', 'n', 'f') \
145         ATOM_ITEM(STBL, 's', 't', 'b', 'l') \
146         ATOM_ITEM(UDTA, 'u', 'd', 't', 'a') \
147         ATOM_ITEM(ILST, 'i', 'l', 's', 't') /* iTunes Metadata list */ \
148         ATOM_ITEM(ARTIST, 0xa9, 'A', 'R', 'T') \
149         ATOM_ITEM(TITLE, 0xa9, 'n', 'a', 'm') \
150         ATOM_ITEM(ALBUM, 0xa9, 'a', 'l', 'b') \
151         ATOM_ITEM(DATE, 0xa9, 'd', 'a', 'y') \
152         ATOM_ITEM(COMMENT, 0xa9, 'c', 'm', 't') \
153         ATOM_ITEM(MDHD, 'm', 'd', 'h', 'd') /* track header */ \
154         ATOM_ITEM(STSD, 's', 't', 's', 'd') /* sample description box */ \
155         ATOM_ITEM(STTS, 's', 't', 't', 's') /* time to sample box */ \
156         ATOM_ITEM(STSZ, 's', 't', 's', 'z') /* sample size box */ \
157         ATOM_ITEM(STCO, 's', 't', 'c', 'o') /* chunk offset box */ \
158         ATOM_ITEM(STSC, 's', 't', 's', 'c') /* sample to chunk box */ \
159         ATOM_ITEM(MP4A, 'm', 'p', '4', 'a') \
160         ATOM_ITEM(META, 'm', 'e', 't', 'a') /* iTunes Metadata box */ \
161         ATOM_ITEM(DATA, 'd', 'a', 't', 'a') /* iTunes Metadata data box */ \
162
163 #define ATOM_ITEM(_name, a, b, c, d) ATOM_ ## _name,
164 enum atom {ATOM_ITEMS};
165 #undef ATOM_ITEM
166
167 static uint8_t atom_name_to_type(uint8_t *p)
168 {
169         #define ATOM_VALUE(a, b, c, d) ((a << 24) + (b << 16) + (c << 8) + d)
170         #define ATOM_ITEM(_name, a, b, c, d) \
171                 {.name = # _name, .val = ATOM_VALUE(a, b, c, d)},
172         static const struct {
173                 const char *name;
174                 uint32_t val;
175         } atom_table[] = {ATOM_ITEMS};
176         #undef ATOM_ITEM
177         uint32_t val = read_u32_be(p);
178
179         for (uint8_t n = 0; n < ARRAY_SIZE(atom_table); n++)
180                 if (val == atom_table[n].val)
181                         return n;
182         return 255;
183 }
184
185 /* read atom header, atom size is returned with header included. */
186 static int atom_read_header(struct mp4 *f, uint8_t *atom_type,
187                 uint8_t *header_size, uint64_t *atom_size)
188 {
189         uint32_t size;
190         int ret;
191         uint8_t atom_header[8];
192
193         ret = read_data(f, atom_header, 8);
194         if (ret <= 0)
195                 return ret;
196         size = read_u32_be(atom_header);
197         if (size == 1) { /* 64 bit atom size */
198                 if (header_size)
199                         *header_size = 16;
200                 ret = read_int64(f, atom_size);
201                 if (ret <= 0)
202                         return ret;
203         } else {
204                 if (header_size)
205                         *header_size = 8;
206                 if (atom_size)
207                         *atom_size = size;
208         }
209         *atom_type = atom_name_to_type(atom_header + 4);
210         return 1;
211 }
212
213 static int64_t get_position(const struct mp4 *f)
214 {
215         return f->current_position;
216 }
217
218 static int32_t set_position(struct mp4 *f, int64_t position)
219 {
220         f->cb->seek(f->cb->user_data, position);
221         f->current_position = position;
222
223         return 0;
224 }
225
226 static int read_stsz(struct mp4 *f)
227 {
228         int ret;
229         int32_t i;
230         struct mp4_track *t;
231
232         if (f->total_tracks == 0)
233                 return -1;
234         t = f->track[f->total_tracks - 1];
235         ret = read_int8(f, NULL); /* version */
236         if (ret <= 0)
237                 return ret;
238         ret = read_int24(f, NULL); /* flags */
239         if (ret <= 0)
240                 return ret;
241         ret = read_int32(f, &t->stsz_sample_size);
242         if (ret <= 0)
243                 return ret;
244         ret = read_int32(f, &t->stsz_sample_count);
245         if (ret <= 0)
246                 return ret;
247         if (t->stsz_sample_size != 0)
248                 return 1;
249         t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
250         for (i = 0; i < t->stsz_sample_count; i++) {
251                 ret = read_int32(f, &t->stsz_table[i]);
252                 if (ret <= 0)
253                         return ret;
254         }
255         return 1;
256 }
257
258 static int read_stts(struct mp4 *f)
259 {
260         int ret;
261         int32_t i;
262         struct mp4_track *t;
263
264         if (f->total_tracks == 0)
265                 return -1;
266         t = f->track[f->total_tracks - 1];
267         if (t->stts_entry_count)
268                 return 0;
269         ret = read_int8(f, NULL); /* version */
270         if (ret <= 0)
271                 return ret;
272         ret = read_int24(f, NULL); /* flags */
273         if (ret <= 0)
274                 return ret;
275         ret = read_int32(f, &t->stts_entry_count);
276         if (ret <= 0)
277                 return ret;
278         t->stts_sample_count = para_malloc(t->stts_entry_count
279                 * sizeof(int32_t));
280         for (i = 0; i < t->stts_entry_count; i++) {
281                 ret = read_int32(f, &t->stts_sample_count[i]);
282                 if (ret <= 0)
283                         return ret;
284                 ret = read_int32(f, NULL); /* sample delta */
285                 if (ret <= 0)
286                         return ret;
287         }
288         return 1;
289 }
290
291 static int read_stsc(struct mp4 *f)
292 {
293         int ret;
294         int32_t i;
295         struct mp4_track *t;
296
297         if (f->total_tracks == 0)
298                 return -1;
299         t = f->track[f->total_tracks - 1];
300
301         ret = read_int8(f, NULL); /* version */
302         if (ret <= 0)
303                 return ret;
304         ret = read_int24(f, NULL); /* flags */
305         if (ret <= 0)
306                 return ret;
307         ret = read_int32(f, &t->stsc_entry_count);
308         if (ret <= 0)
309                 return ret;
310         t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
311         t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
312                 * sizeof (int32_t));
313         for (i = 0; i < t->stsc_entry_count; i++) {
314                 ret = read_int32(f, &t->stsc_first_chunk[i]);
315                 if (ret <= 0)
316                         return ret;
317                 ret = read_int32(f, &t->stsc_samples_per_chunk[i]);
318                 if (ret <= 0)
319                         return ret;
320                 ret = read_int32(f, NULL); /* sample desc index */
321                 if (ret <= 0)
322                         return ret;
323         }
324         return 1;
325 }
326
327 static int read_stco(struct mp4 *f)
328 {
329         int ret;
330         int32_t i;
331         struct mp4_track *t;
332
333         if (f->total_tracks == 0)
334                 return -1;
335         t = f->track[f->total_tracks - 1];
336
337         ret = read_int8(f, NULL); /* version */
338         if (ret <= 0)
339                 return ret;
340         ret = read_int24(f, NULL); /* flags */
341         if (ret <= 0)
342                 return ret;
343         ret = read_int32(f, &t->stco_entry_count);
344         if (ret <= 0)
345                 return ret;
346         t->stco_chunk_offset = para_malloc(t->stco_entry_count
347                 * sizeof(int32_t));
348         for (i = 0; i < t->stco_entry_count; i++) {
349                 ret = read_int32(f, &t->stco_chunk_offset[i]);
350                 if (ret <= 0)
351                         return ret;
352         }
353         return 1;
354 }
355
356 static int read_mp4a(struct mp4 *f)
357 {
358         int ret;
359         int32_t i;
360         struct mp4_track *t;
361
362         if (f->total_tracks == 0)
363                 return -1;
364         t = f->track[f->total_tracks - 1];
365
366         for (i = 0; i < 6; i++) {
367                 ret = read_int8(f, NULL); /* reserved */
368                 if (ret <= 0)
369                         return ret;
370         }
371         ret = read_int16(f, NULL); /* data_reference_index */
372         if (ret <= 0)
373                 return ret;
374         ret = read_int32(f, NULL); /* reserved */
375         if (ret <= 0)
376                 return ret;
377         ret = read_int32(f, NULL); /* reserved */
378         if (ret <= 0)
379                 return ret;
380         ret = read_int16(f, &t->channelCount);
381         if (ret <= 0)
382                 return ret;
383         ret = read_int16(f, NULL);
384         if (ret <= 0)
385                 return ret;
386         ret = read_int16(f, NULL);
387         if (ret <= 0)
388                 return ret;
389         ret = read_int16(f, NULL);
390         if (ret <= 0)
391                 return ret;
392         return read_int16(f, &t->sampleRate);
393 }
394
395 static int read_stsd(struct mp4 *f)
396 {
397         int ret;
398         uint32_t i, entry_count;
399         struct mp4_track *t;
400
401         if (f->total_tracks == 0)
402                 return -1;
403         t = f->track[f->total_tracks - 1];
404         ret = read_int8(f, NULL); /* version */
405         if (ret <= 0)
406                 return ret;
407         ret = read_int24(f, NULL); /* flags */
408         if (ret <= 0)
409                 return ret;
410         ret = read_int32(f, &entry_count);
411         if (ret <= 0)
412                 return ret;
413         for (i = 0; i < entry_count; i++) {
414                 uint64_t skip = get_position(f);
415                 uint64_t size;
416                 uint8_t atom_type = 0;
417                 ret = atom_read_header(f, &atom_type, NULL, &size);
418                 if (ret <= 0)
419                         return ret;
420                 skip += size;
421                 if (!f->audio_track && atom_type == ATOM_MP4A) {
422                         f->audio_track = t;
423                         read_mp4a(f);
424                 }
425                 set_position(f, skip);
426         }
427         return 1;
428 }
429
430 static const char *get_metadata_name(uint8_t atom_type)
431 {
432         switch (atom_type) {
433         case ATOM_TITLE: return "title";
434         case ATOM_ARTIST: return "artist";
435         case ATOM_ALBUM: return "album";
436         case ATOM_DATE: return "date";
437         case ATOM_COMMENT: return "comment";
438         default: return "unknown";
439         }
440 }
441
442 static int parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
443 {
444         int ret;
445         uint64_t subsize, sumsize;
446         char *value = NULL;
447         uint32_t len = 0;
448         uint64_t destpos;
449         struct mp4_tag *tag;
450
451         for (
452                 sumsize = 0;
453                 sumsize < size;
454                 set_position(f, destpos), sumsize += subsize
455         ) {
456                 uint8_t atom_type;
457                 uint8_t header_size = 0;
458                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
459                 if (ret <= 0)
460                         goto fail;
461                 destpos = get_position(f) + subsize - header_size;
462                 if (atom_type != ATOM_DATA)
463                         continue;
464                 ret = read_int8(f, NULL); /* version */
465                 if (ret <= 0)
466                         goto fail;
467                 ret = read_int24(f, NULL); /* flags */
468                 if (ret <= 0)
469                         goto fail;
470                 ret = read_int32(f, NULL); /* reserved */
471                 if (ret <= 0)
472                         goto fail;
473                 ret = -ERRNO_TO_PARA_ERROR(EINVAL);
474                 if (subsize < header_size + 8 || subsize > UINT_MAX)
475                         goto fail;
476                 len = subsize - (header_size + 8);
477                 free(value);
478                 value = para_malloc(len + 1);
479                 ret = read_data(f, value, len);
480                 if (ret <= 0)
481                         goto fail;
482                 value[len] = '\0';
483         }
484         if (!value)
485                 return -ERRNO_TO_PARA_ERROR(EINVAL);
486         f->meta.tags = para_realloc(f->meta.tags, (f->meta.count + 1)
487                 * sizeof(struct mp4_tag));
488         tag = f->meta.tags + f->meta.count;
489         tag->item = para_strdup(get_metadata_name(parent));
490         tag->value = value;
491         tag->len = len;
492         f->meta.count++;
493         return 1;
494 fail:
495         free(value);
496         return ret;
497 }
498
499 static int read_mdhd(struct mp4 *f)
500 {
501         int ret;
502         uint32_t version;
503         struct mp4_track *t;
504
505         if (f->total_tracks == 0)
506                 return -1;
507         t = f->track[f->total_tracks - 1];
508
509         ret = read_int32(f, &version);
510         if (ret <= 0)
511                 return ret;
512         if (version == 1) {
513                 ret = read_int64(f, NULL); /* creation-time */
514                 if (ret <= 0)
515                         return ret;
516                 ret = read_int64(f, NULL); /* modification-time */
517                 if (ret <= 0)
518                         return ret;
519                 ret = read_int32(f, &t->timeScale);
520                 if (ret <= 0)
521                         return ret;
522                 ret = read_int64(f, &t->duration);
523                 if (ret <= 0)
524                         return ret;
525         } else { //version == 0
526                 uint32_t temp;
527
528                 ret = read_int32(f, NULL); /* creation-time */
529                 if (ret <= 0)
530                         return ret;
531                 ret = read_int32(f, NULL); /* modification-time */
532                 if (ret <= 0)
533                         return ret;
534                 ret = read_int32(f, &t->timeScale);
535                 if (ret <= 0)
536                         return ret;
537                 ret = read_int32(f, &temp);
538                 if (ret <= 0)
539                         return ret;
540                 t->duration = (temp == (uint32_t) (-1))?
541                         (uint64_t) (-1) : (uint64_t) (temp);
542         }
543         ret = read_int16(f, NULL);
544         if (ret <= 0)
545                 return ret;
546         ret = read_int16(f, NULL);
547         if (ret <= 0)
548                 return ret;
549         return 1;
550 }
551
552 static int32_t read_ilst(struct mp4 *f, int32_t size)
553 {
554         int ret;
555         uint64_t sumsize = 0;
556
557         while (sumsize < size) {
558                 uint8_t atom_type;
559                 uint64_t subsize, destpos;
560                 uint8_t header_size = 0;
561                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
562                 if (ret <= 0)
563                         return ret;
564                 destpos = get_position(f) + subsize - header_size;
565                 switch (atom_type) {
566                 case ATOM_ARTIST:
567                 case ATOM_TITLE:
568                 case ATOM_ALBUM:
569                 case ATOM_COMMENT:
570                 case ATOM_DATE:
571                         ret = parse_tag(f, atom_type, subsize - header_size);
572                         if (ret <= 0)
573                                 return ret;
574                 }
575                 set_position(f, destpos);
576                 sumsize += subsize;
577         }
578         return 1;
579 }
580
581 static int32_t read_meta(struct mp4 *f, uint64_t size)
582 {
583         int ret;
584         uint64_t subsize, sumsize = 0;
585         uint8_t atom_type;
586         uint8_t header_size = 0;
587
588         ret = read_int8(f, NULL); /* version */
589         if (ret <= 0)
590                 return ret;
591         ret = read_int24(f, NULL); /* flags */
592         if (ret <= 0)
593                 return ret;
594         while (sumsize < (size - (header_size + 4))) {
595                 ret = atom_read_header(f, &atom_type, &header_size, &subsize);
596                 if (ret <= 0)
597                         return ret;
598                 if (subsize <= header_size + 4)
599                         return 1;
600                 if (atom_type == ATOM_ILST) {
601                         f->ilst_offset = get_position(f) - header_size;
602                         f->ilst_size = subsize;
603                         ret = read_ilst(f, subsize - (header_size + 4));
604                         if (ret <= 0)
605                                 return ret;
606                 } else
607                         set_position(f, get_position(f) + subsize - header_size);
608                 sumsize += subsize;
609         }
610         return 1;
611 }
612
613 static bool need_atom(uint8_t atom_type, bool meta_only)
614 {
615         /* these are needed in any case */
616         switch (atom_type) {
617         case ATOM_STSD:
618         case ATOM_META:
619         case ATOM_TRAK:
620         case ATOM_MDIA:
621         case ATOM_MINF:
622         case ATOM_STBL:
623         case ATOM_UDTA:
624                 return true;
625         }
626         /* meta-only opens don't need anything else */
627         if (meta_only)
628                 return false;
629         /* these are only required for regular opens */
630         switch (atom_type) {
631         case ATOM_STTS:
632         case ATOM_STSZ:
633         case ATOM_STCO:
634         case ATOM_STSC:
635         case ATOM_MDHD:
636                 return true;
637         }
638         return false;
639 }
640
641 /* parse atoms that are sub atoms of other atoms */
642 static int parse_sub_atoms(struct mp4 *f, uint64_t total_size, bool meta_only)
643 {
644         int ret;
645         uint64_t dest, size, end = get_position(f) + total_size;
646
647         for (dest = get_position(f); dest < end; set_position(f, dest)) {
648                 uint8_t header_size, atom_type;
649                 ret = atom_read_header(f, &atom_type, &header_size, &size);
650                 if (ret <= 0)
651                         return ret;
652                 if (size == 0)
653                         return -1;
654                 dest = get_position(f) + size - header_size;
655                 if (atom_type == ATOM_TRAK) {
656                         if (f->total_tracks >= MAX_TRACKS)
657                                 return -1;
658                         f->total_tracks++;
659                         f->track[f->total_tracks - 1] = para_calloc(
660                                 sizeof(struct mp4_track));
661                 } else if (atom_type == ATOM_UDTA) {
662                         f->udta_offset = get_position(f) - header_size;
663                         f->udta_size = size;
664                 }
665                 if (!need_atom(atom_type, meta_only))
666                         continue;
667                 switch (atom_type) {
668                 case ATOM_STSZ: ret = read_stsz(f); break;
669                 case ATOM_STTS: ret = read_stts(f); break;
670                 case ATOM_STSC: ret = read_stsc(f); break;
671                 case ATOM_STCO: ret = read_stco(f); break;
672                 case ATOM_STSD: ret = read_stsd(f); break;
673                 case ATOM_MDHD: ret = read_mdhd(f); break;
674                 case ATOM_META:
675                         f->meta_offset = get_position(f) - header_size;
676                         f->meta_size = size;
677                         ret = read_meta(f, size);
678                         break;
679                 default:
680                         ret = parse_sub_atoms(f, size - header_size, meta_only);
681                 }
682                 if (ret <= 0)
683                         return ret;
684         }
685         return 1;
686 }
687
688 static int open_file(const struct mp4_callback *cb, bool meta_only, struct mp4 **result)
689 {
690         int ret;
691         uint64_t size;
692         uint8_t atom_type, header_size;
693         struct mp4 *f = para_calloc(sizeof(*f));
694
695         f->cb = cb;
696         while ((ret = atom_read_header(f, &atom_type, &header_size, &size)) > 0) {
697                 f->file_size += size;
698                 f->last_atom = atom_type;
699                 if (atom_type != ATOM_MOOV || size <= header_size) { /* skip */
700                         set_position(f, get_position(f) + size - header_size);
701                         continue;
702                 }
703                 f->moov_offset = get_position(f) - header_size;
704                 f->moov_size = size;
705                 ret = parse_sub_atoms(f, size - header_size, meta_only);
706                 if (ret <= 0)
707                         break;
708         }
709         if (ret < 0) {
710                 ret = -E_MP4_OPEN;
711                 goto fail;
712         }
713         ret = -E_MP4_TRACK;
714         if (!f->audio_track)
715                 goto fail;
716         *result = f;
717         return 1;
718 fail:
719         *result = NULL;
720         free(f);
721         return ret;
722 }
723
724 int mp4_open_read(const struct mp4_callback *cb, struct mp4 **result)
725 {
726         return open_file(cb, false, result);
727 }
728
729 void mp4_close(struct mp4 *f)
730 {
731         int32_t i;
732
733         for (i = 0; i < f->total_tracks; i++) {
734                 if (f->track[i]) {
735                         free(f->track[i]->stsz_table);
736                         free(f->track[i]->stts_sample_count);
737                         free(f->track[i]->stsc_first_chunk);
738                         free(f->track[i]->stsc_samples_per_chunk);
739                         free(f->track[i]->stco_chunk_offset);
740                         free(f->track[i]);
741                 }
742         }
743         for (i = 0; i < f->meta.count; i++) {
744                 free(f->meta.tags[i].item);
745                 free(f->meta.tags[i].value);
746         }
747         free(f->meta.tags);
748         free(f);
749 }
750
751 static int32_t chunk_of_sample(const struct mp4 *f, int32_t sample,
752                 int32_t *chunk)
753 {
754         const struct mp4_track *t = f->audio_track;
755         uint32_t *fc = t->stsc_first_chunk, *spc = t->stsc_samples_per_chunk;
756         int32_t chunk1, chunk1samples, n, total, i;
757
758         for (i = 1, total = 0; i < t->stsc_entry_count; i++, total += n) {
759                 n = (fc[i] - fc[i - 1]) * spc[i - 1]; /* number of samples */
760                 if (sample < total + n)
761                         break;
762         }
763         chunk1 = fc[i - 1];
764         chunk1samples = spc[i - 1];
765         if (chunk1samples != 0)
766                 *chunk = (sample - total) / chunk1samples + chunk1;
767         else
768                 *chunk = 1;
769         return total + (*chunk - chunk1) * chunk1samples;
770 }
771
772 /**
773  * Return the number of milliseconds of the audio track.
774  *
775  * \param f As returned by \ref mp4_open_read(), must not be NULL.
776  */
777 uint64_t mp4_get_duration(const struct mp4 *f)
778 {
779         const struct mp4_track *t = f->audio_track;
780
781         if (t->timeScale == 0)
782                 return 0;
783         return t->duration * 1000 / t->timeScale;
784 }
785
786 int mp4_set_sample_position(struct mp4 *f, int32_t sample)
787 {
788         const struct mp4_track *t = f->audio_track;
789         int32_t offset, chunk, chunk_sample;
790         uint32_t n, srs; /* sample range size */
791
792         if (sample >= t->stsz_sample_count)
793                 return -ERRNO_TO_PARA_ERROR(EINVAL);
794         chunk_sample = chunk_of_sample(f, sample, &chunk);
795         if (t->stsz_sample_size > 0)
796                 srs = (sample - chunk_sample) * t->stsz_sample_size;
797         else {
798                 for (srs = 0, n = chunk_sample; n < sample; n++)
799                         srs += t->stsz_table[n];
800         }
801         if (t->stco_entry_count > 0 && chunk > t->stco_entry_count)
802                 offset = t->stco_chunk_offset[t->stco_entry_count - 1];
803         else if (t->stco_entry_count > 0)
804                 offset = t->stco_chunk_offset[chunk - 1];
805         else
806                 offset = 8;
807         set_position(f, offset + srs);
808         return 1;
809 }
810
811 int32_t mp4_get_sample_size(const struct mp4 *f, int sample)
812 {
813         const struct mp4_track *t = f->audio_track;
814
815         if (t->stsz_sample_size != 0)
816                 return t->stsz_sample_size;
817         return t->stsz_table[sample];
818 }
819
820 uint32_t mp4_get_sample_rate(const struct mp4 *f)
821 {
822         return f->audio_track->sampleRate;
823 }
824
825 uint32_t mp4_get_channel_count(const struct mp4 *f)
826 {
827         return f->audio_track->channelCount ;
828 }
829
830 int32_t mp4_num_samples(const struct mp4 *f)
831 {
832         const struct mp4_track *t = f->audio_track;
833         int32_t i;
834         int32_t total = 0;
835
836         for (i = 0; i < t->stts_entry_count; i++)
837                 total += t->stts_sample_count[i];
838         return total;
839 }
840
841 int mp4_open_meta(const struct mp4_callback *cb, struct mp4 **result)
842 {
843         struct mp4 *f;
844         int ret = open_file(cb, true, &f);
845
846         if (ret < 0)
847                 return ret;
848         if (f->udta_size == 0 || f->meta_size == 0 || f->ilst_size == 0) {
849                 mp4_close(f);
850                 *result = NULL;
851                 return -E_MP4_MISSING_ATOM;
852         }
853         *result = f;
854         return 1;
855 }
856
857 /**
858  * Return the metadata of an mp4 file.
859  *
860  * \param f As returned by either \ref mp4_open_read() or \ref mp4_open_meta().
861  *
862  * The caller is allowed to add, delete or modify the entries of the returned
863  * structure in order to pass the modified version to \ref mp4_meta_update().
864  */
865 struct mp4_metadata *mp4_get_meta(struct mp4 *f)
866 {
867         return &f->meta;
868 }
869
870 /** Total length of an on-disk metadata tag. */
871 #define TAG_LEN(_len) (24 + (_len))
872 static void create_ilst(const struct mp4_metadata *meta, uint8_t *out)
873 {
874         for (unsigned n = 0; n < meta->count; n++) {
875                 struct mp4_tag *tag = meta->tags + n;
876                 unsigned len = strlen(tag->value);
877                 const char *atom_name;
878
879                 if (!strcasecmp(tag->item, "title"))
880                         atom_name = "\xA9" "nam";
881                 else if (!strcasecmp(tag->item, "artist"))
882                         atom_name = "\xA9" "ART";
883                 else if (!strcasecmp(tag->item, "album"))
884                         atom_name = "\xA9" "alb";
885                 else if (!strcasecmp(tag->item, "date"))
886                         atom_name = "\xA9" "day";
887                 else if (!strcasecmp(tag->item, "comment"))
888                         atom_name = "\xA9" "cmt";
889                 else
890                         assert(false);
891                 write_u32_be(out, TAG_LEN(len));
892                 memcpy(out + 4, atom_name, 4);
893                 write_u32_be(out + 8, 8 /* data atom header */
894                         + 8 /* flags + reserved */
895                         + len);
896                 memcpy(out + 12, "data", 4);
897                 write_u32_be(out + 16, 1); /* flags */
898                 write_u32_be(out + 20, 0); /* reserved */
899                 memcpy(out + 24, tag->value, len);
900                 out += TAG_LEN(len);
901         }
902 }
903
904 static void *modify_moov(struct mp4 *f, uint32_t *out_size)
905 {
906         int ret;
907         uint64_t total_base = f->moov_offset + 8;
908         uint32_t total_size = (uint32_t) (f->moov_size - 8);
909         uint32_t new_ilst_size = 0;
910         void *out_buffer;
911         uint8_t *p_out;
912         int32_t size_delta;
913         uint32_t tmp;
914
915         for (unsigned n = 0; n < f->meta.count; n++)
916                 new_ilst_size += TAG_LEN(strlen(f->meta.tags[n].value));
917         size_delta = new_ilst_size - (f->ilst_size - 8);
918         *out_size = total_size + size_delta;
919         out_buffer = para_malloc(*out_size);
920         p_out = out_buffer;
921         set_position(f, total_base);
922         ret = read_data(f, p_out, f->udta_offset - total_base);
923         if (ret <= 0)
924                 return NULL;
925         p_out += f->udta_offset - total_base;
926         ret = read_int32(f, &tmp);
927         if (ret <= 0)
928                 return NULL;
929         write_u32_be(p_out, tmp + size_delta);
930         p_out += 4;
931         ret = read_data(f, p_out, 4);
932         if (ret <= 0)
933                 return NULL;
934         p_out += 4;
935         ret = read_data(f, p_out, f->meta_offset - f->udta_offset - 8);
936         if (ret <= 0)
937                 return NULL;
938         p_out += f->meta_offset - f->udta_offset - 8;
939         ret = read_int32(f, &tmp);
940         if (ret <= 0)
941                 return NULL;
942         write_u32_be(p_out, tmp + size_delta);
943         p_out += 4;
944         ret = read_data(f, p_out, 4);
945         if (ret <= 0)
946                 return NULL;
947         p_out += 4;
948         ret = read_data(f, p_out, f->ilst_offset - f->meta_offset - 8);
949         if (ret <= 0)
950                 return NULL;
951         p_out += f->ilst_offset - f->meta_offset - 8;
952         ret = read_int32(f, &tmp);
953         if (ret <= 0)
954                 return NULL;
955         write_u32_be(p_out, tmp + size_delta);
956         p_out += 4;
957         ret = read_data(f, p_out, 4);
958         if (ret <= 0)
959                 return NULL;
960         p_out += 4;
961         create_ilst(&f->meta, p_out);
962         p_out += new_ilst_size;
963         set_position(f, f->ilst_offset + f->ilst_size);
964         ret = read_data(f, p_out, total_size - (f->ilst_offset - total_base)
965                 - f->ilst_size);
966         if (ret <= 0)
967                 return NULL;
968         return out_buffer;
969 }
970
971 static int32_t write_data(struct mp4 *f, void *data, uint32_t size)
972 {
973         int32_t result = 1;
974
975         result = f->cb->write(f->cb->user_data, data, size);
976
977         f->current_position += size;
978
979         return result;
980 }
981
982 static int32_t write_int32(struct mp4 *f, uint32_t data)
983 {
984         int8_t temp[4];
985         write_u32_be(temp, data);
986         return write_data(f, temp, sizeof(temp));
987 }
988
989 int32_t mp4_meta_update(struct mp4 *f)
990 {
991         void *new_moov_data;
992         uint32_t new_moov_size;
993
994         set_position(f, 0);
995         new_moov_data = modify_moov(f, &new_moov_size);
996         if (!new_moov_data ) {
997                 mp4_close(f);
998                 return 0;
999         }
1000         /* copy moov atom to end of the file */
1001         if (f->last_atom != ATOM_MOOV) {
1002                 char *free_data = "free";
1003
1004                 /* rename old moov to free */
1005                 set_position(f, f->moov_offset + 4);
1006                 write_data(f, free_data, 4);
1007
1008                 set_position(f, f->file_size);
1009                 write_int32(f, new_moov_size + 8);
1010                 write_data(f, "moov", 4);
1011                 write_data(f, new_moov_data, new_moov_size);
1012         } else {
1013                 set_position(f, f->moov_offset);
1014                 write_int32(f, new_moov_size + 8);
1015                 write_data(f, "moov", 4);
1016                 write_data(f, new_moov_data, new_moov_size);
1017         }
1018         free(new_moov_data);
1019         f->cb->truncate(f->cb->user_data);
1020         return 1;
1021 }
1022
1023 static char *meta_find_by_name(const struct mp4 *f, const char *item)
1024 {
1025         uint32_t i;
1026
1027         for (i = 0; i < f->meta.count; i++)
1028                 if (!strcasecmp(f->meta.tags[i].item, item))
1029                         return para_strdup(f->meta.tags[i].value);
1030         return NULL;
1031 }
1032
1033 /**
1034  * Return the value of the artist meta tag of an mp4 file.
1035  *
1036  * \param f Must not be NULL.
1037  *
1038  * \return If the file does not contain this metadata tag, the function returns
1039  * NULL. Otherwise, a copy of the tag value is returned. The caller should free
1040  * this memory when it is no longer needed.
1041  */
1042 char *mp4_meta_get_artist(const struct mp4 *f)
1043 {
1044         return meta_find_by_name(f, "artist");
1045 }
1046
1047 /**
1048  * Return the value of the title meta tag of an mp4 file.
1049  *
1050  * \param f See \ref mp4_meta_get_artist().
1051  * \return See \ref mp4_meta_get_artist().
1052  */
1053 char *mp4_meta_get_title(const struct mp4 *f)
1054 {
1055         return meta_find_by_name(f, "title");
1056 }
1057
1058 /**
1059  * Return the value of the date meta tag of an mp4 file.
1060  *
1061  * \param f See \ref mp4_meta_get_artist().
1062  * \return See \ref mp4_meta_get_artist().
1063  */
1064 char *mp4_meta_get_date(const struct mp4 *f)
1065 {
1066         return meta_find_by_name(f, "date");
1067 }
1068
1069 /**
1070  * Return the value of the album meta tag of an mp4 file.
1071  *
1072  * \param f See \ref mp4_meta_get_artist().
1073  * \return See \ref mp4_meta_get_artist().
1074  */
1075 char *mp4_meta_get_album(const struct mp4 *f)
1076 {
1077         return meta_find_by_name(f, "album");
1078 }
1079
1080 /**
1081  * Return the value of the comment meta tag of an mp4 file.
1082  *
1083  * \param f See \ref mp4_meta_get_artist().
1084  * \return See \ref mp4_meta_get_artist().
1085  */
1086 char *mp4_meta_get_comment(const struct mp4 *f)
1087 {
1088         return meta_find_by_name(f, "comment");
1089 }