]> iEval git - fdkaac.git/blame_incremental - src/m4af.c
Imported Upstream version 0.6.2
[fdkaac.git] / src / m4af.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
4 */
5#if HAVE_CONFIG_H
6# include "config.h"
7#endif
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <assert.h>
12#include <time.h>
13#if HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#if HAVE_INTTYPES_H
17# include <inttypes.h>
18#elif defined _MSC_VER
19# define PRId64 "I64d"
20#endif
21#include "m4af.h"
22#include "m4af_endian.h"
23
24#define m4af_realloc(memory,size) realloc(memory, size)
25#define m4af_free(memory) free(memory)
26#define m4af_max(a,b) ((a)<(b)?(b):(a))
27
28#define M4AF_ATOM_WILD 0xffffffff
29
30typedef struct m4af_sample_entry_t {
31 uint32_t size;
32 uint32_t delta;
33} m4af_sample_entry_t;
34
35typedef struct m4af_chunk_entry_t {
36 int64_t offset;
37 uint32_t size;
38 uint32_t samples_per_chunk;
39 uint32_t duration;
40} m4af_chunk_entry_t;
41
42typedef struct m4af_track_t {
43 uint32_t codec;
44 uint32_t timescale;
45 uint16_t num_channels;
46 int64_t creation_time;
47 int64_t modification_time;
48 int64_t duration;
49 uint32_t frame_duration;
50 uint32_t encoder_delay;
51 uint32_t padding;
52 uint8_t *decSpecificInfo;
53 uint32_t decSpecificInfoSize;
54 uint32_t bufferSizeDB;
55 uint32_t maxBitrate;
56 uint32_t avgBitrate;
57 int is_vbr;
58
59 m4af_sample_entry_t *sample_table;
60 uint32_t num_samples;
61 uint32_t sample_table_capacity;
62
63 m4af_chunk_entry_t *chunk_table;
64 uint32_t num_chunks;
65 uint32_t chunk_table_capacity;
66
67 uint8_t *chunk_buffer;
68 uint32_t chunk_size;
69 uint32_t chunk_capacity;
70
71 /* temporary, to help parsing */
72 uint64_t stsc_pos;
73 uint64_t stsc_size;
74
75 uint64_t stts_pos;
76 uint64_t stts_size;
77} m4af_track_t;
78
79struct m4af_ctx_t {
80 uint32_t timescale;
81 int64_t creation_time;
82 int64_t modification_time;
83 int64_t mdat_pos;
84 int64_t mdat_size;
85 int priming_mode;
86 int last_error;
87
88 m4af_itmf_entry_t *itmf_table;
89 uint32_t num_tags;
90 uint32_t itmf_table_capacity;
91
92 m4af_io_callbacks_t io;
93 void *io_cookie;
94
95 uint16_t num_tracks;
96 m4af_track_t track[2];
97
98 m4af_itmf_entry_t current_tag;
99};
100
101typedef struct m4af_box_parser_t {
102 uint32_t name;
103 int (*handler)(m4af_ctx_t *ctx, uint32_t name, uint64_t size);
104} m4af_box_parser_t;
105
106static
107int m4af_write_null_cb(void *cookie, const void *data, uint32_t size)
108{
109 int64_t *pos = cookie;
110 *pos += size;
111 return 0;
112}
113static
114int m4af_seek_null_cb(void *cookie, int64_t off, int whence)
115{
116 int64_t *pos = cookie;
117 *pos = off; /* XXX: we use only SEEK_SET */
118 return 0;
119}
120static
121int64_t m4af_tell_null_cb(void *cookie)
122{
123 return *((int64_t*)cookie);
124}
125
126static m4af_io_callbacks_t m4af_null_io_callbacks = {
127 0, m4af_write_null_cb, m4af_seek_null_cb, m4af_tell_null_cb
128};
129
130static
131int64_t m4af_timestamp(void)
132{
133 return (int64_t)(time(0)) + (((1970 - 1904) * 365) + 17) * 24 * 60 * 60;
134}
135
136
137/*
138 * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
139 */
140static
141uint32_t m4af_roundup(uint32_t n)
142{
143 n--;
144 n |= n >> 1;
145 n |= n >> 2;
146 n |= n >> 4;
147 n |= n >> 8;
148 n |= n >> 16;
149 n++;
150 return n;
151}
152
153static
154int64_t m4af_tell(m4af_ctx_t *ctx)
155{
156 int64_t pos = -1;
157 if ((pos = ctx->io.tell(ctx->io_cookie)) < 0)
158 ctx->last_error = M4AF_IO_ERROR;
159 return pos;
160}
161
162static
163int m4af_set_pos(m4af_ctx_t *ctx, int64_t pos)
164{
165 int rc = -1;
166 if ((rc = ctx->io.seek(ctx->io_cookie, pos, SEEK_SET)) < 0)
167 ctx->last_error = M4AF_IO_ERROR;
168 return rc;
169}
170
171static
172int m4af_write(m4af_ctx_t *ctx, const void *data, uint32_t size)
173{
174 int rc = -1;
175 if ((rc = ctx->io.write(ctx->io_cookie, data, size)) < 0)
176 ctx->last_error = M4AF_IO_ERROR;
177 return rc;
178}
179
180static
181int m4af_write16(m4af_ctx_t *ctx, uint32_t data)
182{
183 data = m4af_htob16(data);
184 return m4af_write(ctx, &data, 2);
185}
186
187static
188int m4af_write32(m4af_ctx_t *ctx, uint32_t data)
189{
190 data = m4af_htob32(data);
191 return m4af_write(ctx, &data, 4);
192}
193
194static
195int m4af_write64(m4af_ctx_t *ctx, uint64_t data)
196{
197 data = m4af_htob64(data);
198 return m4af_write(ctx, &data, 8);
199}
200
201static
202int m4af_write24(m4af_ctx_t *ctx, uint32_t data)
203{
204 data = m4af_htob32(data << 8);
205 return m4af_write(ctx, &data, 3);
206}
207
208static
209void m4af_write32_at(m4af_ctx_t *ctx, int64_t pos, uint32_t value)
210{
211 int64_t current_pos = m4af_tell(ctx);
212 m4af_set_pos(ctx, pos);
213 m4af_write32(ctx, value);
214 m4af_set_pos(ctx, current_pos);
215}
216
217m4af_ctx_t *m4af_create(uint32_t codec, uint32_t timescale,
218 m4af_io_callbacks_t *io, void *io_cookie)
219{
220 m4af_ctx_t *ctx;
221 int64_t timestamp;
222
223 if (codec != M4AF_FOURCC('m','p','4','a') &&
224 codec != M4AF_FOURCC('a','l','a','c'))
225 return 0;
226 if ((ctx = m4af_realloc(0, sizeof(m4af_ctx_t))) == 0)
227 return 0;
228 memset(ctx, 0, sizeof(m4af_ctx_t));
229 memcpy(&ctx->io, io, sizeof(m4af_io_callbacks_t));
230 ctx->io_cookie = io_cookie;
231 ctx->timescale = timescale;
232 timestamp = m4af_timestamp();
233 ctx->creation_time = timestamp;
234 ctx->modification_time = timestamp;
235 ctx->num_tracks = 1;
236 ctx->track[0].codec = codec;
237 ctx->track[0].timescale = timescale;
238 ctx->track[0].creation_time = timestamp;
239 ctx->track[0].modification_time = timestamp;
240 ctx->track[0].num_channels = 2;
241 return ctx;
242}
243
244static
245void m4af_free_itmf_table(m4af_ctx_t *ctx)
246{
247 uint32_t i;
248 m4af_itmf_entry_t *entry = ctx->itmf_table;
249 for (i = 0; i < ctx->num_tags; ++i, ++entry) {
250 if (entry->fcc == M4AF_FOURCC('-','-','-','-'))
251 m4af_free(entry->name);
252 m4af_free(entry->data);
253 }
254 m4af_free(ctx->itmf_table);
255}
256
257static
258void m4af_clear_track(m4af_ctx_t *ctx, int track_idx)
259{
260 m4af_track_t *track = ctx->track + track_idx;
261 if (track->decSpecificInfo)
262 m4af_free(track->decSpecificInfo);
263 if (track->sample_table)
264 m4af_free(track->sample_table);
265 if (track->chunk_table)
266 m4af_free(track->chunk_table);
267 if (track->chunk_buffer)
268 m4af_free(track->chunk_buffer);
269 memset(track, 0, sizeof(m4af_track_t));
270}
271
272void m4af_teardown(m4af_ctx_t **ctxp)
273{
274 unsigned i;
275 m4af_ctx_t *ctx = *ctxp;
276 for (i = 0; i < ctx->num_tracks; ++i)
277 m4af_clear_track(ctx, i);
278 if (ctx->itmf_table)
279 m4af_free_itmf_table(ctx);
280 m4af_free(ctx);
281 *ctxp = 0;
282}
283
284void m4af_set_num_channels(m4af_ctx_t *ctx, uint32_t track_idx,
285 uint16_t channels)
286{
287 ctx->track[track_idx].num_channels = channels;
288}
289
290void m4af_set_fixed_frame_duration(m4af_ctx_t *ctx, uint32_t track_idx,
291 uint32_t length)
292{
293 ctx->track[track_idx].frame_duration = length;
294}
295
296int m4af_set_decoder_specific_info(m4af_ctx_t *ctx, uint32_t track_idx,
297 uint8_t *data, uint32_t size)
298{
299 m4af_track_t *track = &ctx->track[track_idx];
300 if (size > track->decSpecificInfoSize) {
301 uint8_t *memory = m4af_realloc(track->decSpecificInfo, size);
302 if (memory == 0) {
303 ctx->last_error = M4AF_NO_MEMORY;
304 goto DONE;
305 }
306 track->decSpecificInfo = memory;
307 }
308 if (size > 0)
309 memcpy(track->decSpecificInfo, data, size);
310 track->decSpecificInfoSize = size;
311DONE:
312 return ctx->last_error;
313}
314
315void m4af_set_vbr_mode(m4af_ctx_t *ctx, uint32_t track_idx, int is_vbr)
316{
317 m4af_track_t *track = &ctx->track[track_idx];
318 track->is_vbr = is_vbr;
319}
320
321void m4af_set_priming(m4af_ctx_t *ctx, uint32_t track_idx,
322 uint32_t encoder_delay, uint32_t padding)
323{
324 m4af_track_t *track = &ctx->track[track_idx];
325 track->encoder_delay = encoder_delay;
326 track->padding = padding;
327}
328
329void m4af_set_priming_mode(m4af_ctx_t *ctx, int mode)
330{
331 ctx->priming_mode = mode;
332}
333
334static
335int m4af_add_sample_entry(m4af_ctx_t *ctx, uint32_t track_idx,
336 uint32_t size, uint32_t delta)
337{
338 m4af_track_t *track = &ctx->track[track_idx];
339 m4af_sample_entry_t *entry;
340
341 if (ctx->last_error)
342 return -1;
343 if (track->num_samples == track->sample_table_capacity) {
344 uint32_t new_size = track->sample_table_capacity;
345 new_size = new_size ? new_size * 2 : 1;
346 entry = m4af_realloc(track->sample_table, new_size * sizeof(*entry));
347 if (entry == 0) {
348 ctx->last_error = M4AF_NO_MEMORY;
349 return -1;
350 }
351 track->sample_table = entry;
352 track->sample_table_capacity = new_size;
353 }
354 entry = track->sample_table + track->num_samples;
355 entry->size = size;
356 entry->delta = delta;
357 ++track->num_samples;
358 return 0;
359}
360
361static
362int m4af_flush_chunk(m4af_ctx_t *ctx, uint32_t track_idx)
363{
364 m4af_track_t *track = &ctx->track[track_idx];
365 m4af_chunk_entry_t *entry;
366 if (!track->num_chunks || !track->chunk_size)
367 return 0;
368 entry = &track->chunk_table[track->num_chunks - 1];
369 entry->offset = m4af_tell(ctx);
370 m4af_write(ctx, track->chunk_buffer, track->chunk_size);
371 ctx->mdat_size += track->chunk_size;
372 track->chunk_size = 0;
373 return ctx->last_error ? -1 : 0;
374}
375
376static
377int m4af_add_chunk_entry(m4af_ctx_t *ctx, uint32_t track_idx)
378{
379 m4af_track_t *track = &ctx->track[track_idx];
380 m4af_chunk_entry_t *entry;
381 if (track->num_chunks == track->chunk_table_capacity) {
382 uint32_t new_size = track->chunk_table_capacity;
383 new_size = new_size ? new_size * 2 : 1;
384 entry = m4af_realloc(track->chunk_table, new_size * sizeof(*entry));
385 if (entry == 0) {
386 ctx->last_error = M4AF_NO_MEMORY;
387 return -1;
388 }
389 track->chunk_table = entry;
390 track->chunk_table_capacity = new_size;
391 }
392 memset(&track->chunk_table[track->num_chunks++], 0,
393 sizeof(m4af_chunk_entry_t));
394 return 0;
395}
396
397static
398int m4af_update_chunk_table(m4af_ctx_t *ctx, uint32_t track_idx,
399 uint32_t size, uint32_t delta)
400{
401 m4af_track_t *track = &ctx->track[track_idx];
402 m4af_chunk_entry_t *entry;
403 int add_new_chunk = 0;
404
405 if (ctx->last_error)
406 return -1;
407 if (track->num_chunks == 0)
408 add_new_chunk = 1;
409 else {
410 entry = &track->chunk_table[track->num_chunks - 1];
411 if (entry->duration + delta > track->timescale / 2)
412 add_new_chunk = 1;
413 }
414 if (add_new_chunk) {
415 m4af_flush_chunk(ctx, track_idx);
416 if (m4af_add_chunk_entry(ctx, track_idx) < 0)
417 return -1;
418 }
419 entry = &track->chunk_table[track->num_chunks - 1];
420 entry->size += size;
421 ++entry->samples_per_chunk;
422 entry->duration += delta;
423 return 0;
424}
425
426static
427void m4af_update_max_bitrate(m4af_ctx_t *ctx, uint32_t track_idx)
428{
429 m4af_track_t *track = &ctx->track[track_idx];
430 uint32_t duration = 0, size = 0, bitrate;
431 m4af_sample_entry_t *ent = track->sample_table + track->num_samples - 1;
432
433 for (; ent >= track->sample_table && duration < track->timescale; --ent) {
434 duration += ent->delta;
435 size += ent->size;
436 }
437 bitrate = (uint32_t)(size * 8.0 * track->timescale / duration + .5);
438 if (bitrate > track->maxBitrate)
439 track->maxBitrate = bitrate;
440}
441
442static
443int m4af_append_sample_to_chunk(m4af_ctx_t *ctx, uint32_t track_idx,
444 const void *data, uint32_t size)
445{
446 m4af_track_t *track = &ctx->track[track_idx];
447 uint32_t newsize = track->chunk_size + size;
448
449 if (ctx->last_error)
450 return -1;
451 if (track->chunk_capacity < newsize) {
452 uint32_t capacity = m4af_roundup(newsize);
453 uint8_t *memory = realloc(track->chunk_buffer, capacity);
454 if (!memory) {
455 ctx->last_error = M4AF_NO_MEMORY;
456 return -1;
457 }
458 track->chunk_buffer = memory;
459 track->chunk_capacity = capacity;
460 }
461 memcpy(track->chunk_buffer + track->chunk_size, data, size);
462 track->chunk_size = newsize;
463 return 0;
464}
465
466int m4af_write_sample(m4af_ctx_t *ctx, uint32_t track_idx, const void *data,
467 uint32_t size, uint32_t duration)
468{
469 m4af_track_t *track = &ctx->track[track_idx];
470 if (track->frame_duration)
471 duration = track->frame_duration;
472 if (size > track->bufferSizeDB)
473 track->bufferSizeDB = size;
474 track->duration += duration;
475 m4af_add_sample_entry(ctx, track_idx, size, duration);
476 m4af_update_chunk_table(ctx, track_idx, size, duration);
477 m4af_update_max_bitrate(ctx, track_idx);
478 m4af_append_sample_to_chunk(ctx, track_idx, data, size);
479 return ctx->last_error;
480}
481
482static
483m4af_itmf_entry_t *m4af_find_itmf_slot(m4af_ctx_t *ctx, uint32_t fcc,
484 const char *name)
485{
486 m4af_itmf_entry_t *entry = ctx->itmf_table;
487
488 if (name)
489 fcc = M4AF_FOURCC('-','-','-','-');
490
491 if (fcc != M4AF_TAG_ARTWORK)
492 for (; entry != ctx->itmf_table + ctx->num_tags; ++entry)
493 if (fcc == entry->fcc && (!name || !strcmp(name, entry->name)))
494 return entry;
495
496 if (ctx->num_tags == ctx->itmf_table_capacity) {
497 uint32_t new_size = ctx->itmf_table_capacity;
498 new_size = new_size ? new_size * 2 : 1;
499 entry = m4af_realloc(ctx->itmf_table, new_size * sizeof(*entry));
500 if (entry == 0) {
501 ctx->last_error = M4AF_NO_MEMORY;
502 return 0;
503 }
504 ctx->itmf_table = entry;
505 ctx->itmf_table_capacity = new_size;
506 }
507 entry = &ctx->itmf_table[ctx->num_tags++];
508 memset(entry, 0, sizeof(m4af_itmf_entry_t));
509 entry->fcc = fcc;
510 if (name) {
511 char *name_copy = m4af_realloc(0, strlen(name) + 1);
512 if (!name_copy) {
513 ctx->last_error = M4AF_NO_MEMORY;
514 --ctx->num_tags;
515 return 0;
516 }
517 strcpy(name_copy, name);
518 entry->name = name_copy;
519 }
520 return entry;
521}
522
523int m4af_add_itmf_long_tag(m4af_ctx_t *ctx, const char *name,
524 const char *data)
525{
526 m4af_itmf_entry_t *entry;
527 char *data_copy = 0;
528 size_t name_len = strlen(name);
529 size_t data_len = strlen(data);
530 if (!name_len || !data_len)
531 return 0;
532
533 if ((entry = m4af_find_itmf_slot(ctx, 0, name)) == 0)
534 goto FAIL;
535 entry->type_code = M4AF_UTF8;
536 if ((data_copy = m4af_realloc(entry->data, data_len)) == 0) {
537 ctx->last_error = M4AF_NO_MEMORY;
538 goto FAIL;
539 }
540 memcpy(data_copy, data, data_len);
541 entry->data = data_copy;
542 entry->data_size = data_len;
543 return 0;
544FAIL:
545 return ctx->last_error;
546}
547
548int m4af_add_itmf_short_tag(m4af_ctx_t *ctx, uint32_t fcc,
549 uint32_t type_code, const void *data,
550 uint32_t data_size)
551{
552 m4af_itmf_entry_t *entry;
553 char *data_copy = 0;
554
555 if (!data_size)
556 return 0;
557 if ((entry = m4af_find_itmf_slot(ctx, fcc, 0)) == 0)
558 goto FAIL;
559 entry->type_code = type_code;
560 if ((data_copy = m4af_realloc(entry->data, data_size)) == 0) {
561 ctx->last_error = M4AF_NO_MEMORY;
562 goto FAIL;
563 }
564 memcpy(data_copy, data, data_size);
565 entry->data = data_copy;
566 entry->data_size = data_size;
567 return 0;
568FAIL:
569 return ctx->last_error;
570}
571
572int m4af_add_itmf_string_tag(m4af_ctx_t *ctx, uint32_t fcc, const char *data)
573{
574 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_UTF8, data, strlen(data));
575}
576
577int m4af_add_itmf_int8_tag(m4af_ctx_t *ctx, uint32_t fcc, int value)
578{
579 uint8_t data = value;
580 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 1);
581}
582
583int m4af_add_itmf_int16_tag(m4af_ctx_t *ctx, uint32_t fcc, int value)
584{
585 uint16_t data = m4af_htob16(value);
586 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 2);
587}
588
589int m4af_add_itmf_int32_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t value)
590{
591 uint32_t data = m4af_htob32(value);
592 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 4);
593}
594
595int m4af_add_itmf_int64_tag(m4af_ctx_t *ctx, uint32_t fcc, uint64_t value)
596{
597 uint64_t data = m4af_htob64(value);
598 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 8);
599}
600
601int m4af_add_itmf_track_tag(m4af_ctx_t *ctx, int track, int total)
602{
603 uint16_t data[4] = { 0 };
604 data[1] = m4af_htob16(track);
605 data[2] = m4af_htob16(total);
606 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('t','r','k','n'),
607 M4AF_IMPLICIT, &data, 8);
608}
609
610int m4af_add_itmf_disk_tag(m4af_ctx_t *ctx, int disk, int total)
611{
612 uint16_t data[3] = { 0 };
613 data[1] = m4af_htob16(disk);
614 data[2] = m4af_htob16(total);
615 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('d','i','s','k'),
616 M4AF_IMPLICIT, &data, 6);
617}
618
619int m4af_add_itmf_genre_tag(m4af_ctx_t *ctx, int genre)
620{
621 uint16_t data = m4af_htob16(genre);
622 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('g','n','r','e'),
623 M4AF_IMPLICIT, &data, 2);
624}
625
626static
627int m4af_set_iTunSMPB(m4af_ctx_t *ctx)
628{
629 const char *fmt = " 00000000 %08X %08X %08X%08X 00000000 00000000 "
630 "00000000 00000000 00000000 00000000 00000000 00000000";
631 m4af_track_t *track = &ctx->track[0];
632 char buf[256];
633 uint64_t length = track->duration - track->encoder_delay - track->padding;
634 sprintf(buf, fmt, track->encoder_delay, track->padding,
635 (uint32_t)(length >> 32), (uint32_t)length);
636 return m4af_add_itmf_long_tag(ctx, "iTunSMPB", buf);
637}
638
639static
640uint32_t m4af_update_box_size(m4af_ctx_t *ctx, int64_t pos)
641{
642 int64_t current_pos = m4af_tell(ctx);
643 m4af_set_pos(ctx, pos);
644 m4af_write32(ctx, current_pos - pos);
645 m4af_set_pos(ctx, current_pos);
646 return current_pos - pos;
647}
648
649static
650void m4af_write_descriptor(m4af_ctx_t *ctx, uint32_t tag, uint32_t size)
651{
652 uint8_t buf[5];
653 buf[0] = tag;
654 buf[1] = ((size >> 21) | 0x80);
655 buf[2] = ((size >> 14) | 0x80);
656 buf[3] = ((size >> 7) | 0x80);
657 buf[4] = (size & 0x7f);
658 m4af_write(ctx, buf, 5);
659}
660
661static
662void m4af_write_ftyp_box(m4af_ctx_t *ctx)
663{
664 m4af_write(ctx, "\0\0\0\040""ftypM4A \0\0\0\0M4A mp42isom\0\0\0\0", 32);
665}
666
667static
668void m4af_write_free_box(m4af_ctx_t *ctx, uint32_t size)
669{
670 int64_t pos = m4af_tell(ctx);
671 m4af_write32(ctx, size + 8);
672 m4af_write(ctx, "free", 4);
673 if (size > 0)
674 m4af_set_pos(ctx, pos + size + 8);
675}
676
677int m4af_begin_write(m4af_ctx_t *ctx)
678{
679 m4af_write_ftyp_box(ctx);
680 m4af_write_free_box(ctx, 0);
681 m4af_write(ctx, "\0\0\0\0mdat", 8);
682 ctx->mdat_pos = m4af_tell(ctx);
683 return ctx->last_error;
684}
685
686static
687void m4af_write_stco_box(m4af_ctx_t *ctx, uint32_t track_idx)
688{
689 m4af_track_t *track = &ctx->track[track_idx];
690 uint32_t i;
691 m4af_chunk_entry_t *index = track->chunk_table;
692 int is_co64 = index[track->num_chunks - 1].offset > 0xffffffff;
693 int64_t pos = m4af_tell(ctx);
694
695 m4af_write32(ctx, 0); /* size */
696 m4af_write(ctx, is_co64 ? "co64" : "stco", 4);
697 m4af_write32(ctx, 0); /* version and flags */
698 m4af_write32(ctx, track->num_chunks);
699 for (i = 0; i < track->num_chunks; ++i, ++index) {
700 if (is_co64)
701 m4af_write64(ctx, index->offset);
702 else
703 m4af_write32(ctx, index->offset);
704 }
705 m4af_update_box_size(ctx, pos);
706}
707
708static
709void m4af_write_stsz_box(m4af_ctx_t *ctx, uint32_t track_idx)
710{
711 m4af_track_t *track = &ctx->track[track_idx];
712 m4af_sample_entry_t *index = track->sample_table;
713 uint32_t i;
714 int64_t pos = m4af_tell(ctx);
715 m4af_write(ctx,
716 "\0\0\0\0" /* size */
717 "stsz" /* type */
718 "\0" /* version */
719 "\0\0\0" /* flags */
720 "\0\0\0\0" /* sample_size: 0(variable) */
721 , 16);
722 m4af_write32(ctx, track->num_samples);
723 for (i = 0; i < track->num_samples; ++i, ++index)
724 m4af_write32(ctx, index->size);
725 m4af_update_box_size(ctx, pos);
726}
727
728static
729void m4af_write_stsc_box(m4af_ctx_t *ctx, uint32_t track_idx)
730{
731 m4af_track_t *track = &ctx->track[track_idx];
732 m4af_chunk_entry_t *index = track->chunk_table;
733 uint32_t i, prev_samples_per_chunk = 0, entry_count = 0;
734 int64_t pos = m4af_tell(ctx);
735 m4af_write(ctx,
736 "\0\0\0\0" /* size */
737 "stsc" /* type */
738 "\0" /* version */
739 "\0\0\0" /* flags */
740 "\0\0\0\0" /* entry_count */
741 , 16);
742
743 for (i = 0; i < track->num_chunks; ++i, ++index) {
744 if (index->samples_per_chunk != prev_samples_per_chunk) {
745 ++entry_count;
746 m4af_write32(ctx, i + 1);
747 m4af_write32(ctx, index->samples_per_chunk);
748 m4af_write32(ctx, 1); /* sample_description_index */
749 prev_samples_per_chunk = index->samples_per_chunk;
750 }
751 }
752 m4af_write32_at(ctx, pos + 12, entry_count);
753 m4af_update_box_size(ctx, pos);
754}
755
756static
757void m4af_write_stts_box(m4af_ctx_t *ctx, uint32_t track_idx)
758{
759 m4af_track_t *track = &ctx->track[track_idx];
760 m4af_sample_entry_t *index = track->sample_table;
761 uint32_t i, prev_delta = 0, entry_count = 0, sample_count = 0;
762 int64_t pos = m4af_tell(ctx);
763 m4af_write(ctx,
764 "\0\0\0\0" /* size */
765 "stts" /* type */
766 "\0" /* version */
767 "\0\0\0" /* flags */
768 "\0\0\0\0" /* entry_count */
769 , 16);
770
771 for (i = 0; i < track->num_samples; ++i, ++index) {
772 if (index->delta == prev_delta)
773 ++sample_count;
774 else {
775 ++entry_count;
776 if (sample_count) {
777 m4af_write32(ctx, sample_count);
778 m4af_write32(ctx, prev_delta);
779 }
780 prev_delta = index->delta;
781 sample_count = 1;
782 }
783 }
784 if (sample_count) {
785 m4af_write32(ctx, sample_count);
786 m4af_write32(ctx, prev_delta);
787 }
788 m4af_write32_at(ctx, pos + 12, entry_count);
789 m4af_update_box_size(ctx, pos);
790}
791
792static
793void m4af_write_esds_box(m4af_ctx_t *ctx, uint32_t track_idx)
794{
795 m4af_track_t *track = &ctx->track[track_idx];
796 int64_t pos = m4af_tell(ctx);
797 m4af_write(ctx, "\0\0\0\0esds", 8);
798 m4af_write32(ctx, 0); /* version + flags */
799
800 /* ES_Descriptor */
801 m4af_write_descriptor(ctx, 3, 32 + track->decSpecificInfoSize);
802 m4af_write(ctx, "\0\0\0", 3);
803 /* DecoderConfigDescriptor */
804 m4af_write_descriptor(ctx, 4, 18 + track->decSpecificInfoSize);
805 m4af_write(ctx,
806 "\x40" /* objectTypeIndication: 0x40(Audio ISO/IEC 14496-3)*/
807 "\x15" /* streamType(6): 0x05(AudioStream)
808 * upStream(1) : 0
809 * reserved(1) : 1
810 */
811 , 2);
812 m4af_write24(ctx, track->bufferSizeDB);
813 m4af_write32(ctx, track->maxBitrate);
814 m4af_write32(ctx, track->is_vbr ? 0: track->avgBitrate);
815 /* DecoderSpecificInfo */
816 m4af_write_descriptor(ctx, 5, track->decSpecificInfoSize);
817 m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize);
818 /* SLConfigDescriptor */
819 m4af_write_descriptor(ctx, 6, 1);
820 m4af_write(ctx, "\002", 1); /* predefined */
821
822 m4af_update_box_size(ctx, pos);
823}
824
825static
826void m4af_write_alac_box(m4af_ctx_t *ctx, uint32_t track_idx)
827{
828 m4af_track_t *track = &ctx->track[track_idx];
829 int64_t pos = m4af_tell(ctx);
830 m4af_write(ctx,
831 "\0\0\0\0" /* size */
832 "alac" /* type */
833 "\0" /* version */
834 "\0\0\0" /* flags */
835 , 12);
836 m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize);
837 m4af_update_box_size(ctx, pos);
838}
839
840static
841void m4af_write_mp4a_box(m4af_ctx_t *ctx, uint32_t track_idx)
842{
843 m4af_track_t *track = &ctx->track[track_idx];
844 int64_t pos = m4af_tell(ctx);
845 m4af_write32(ctx, 0); /* size */
846 m4af_write32(ctx, track->codec); /* mp4a or alac */
847 m4af_write(ctx,
848 "\0\0\0\0\0\0" /* reserved */
849 "\0\001" /* data_reference_index: 1 */
850 "\0\0\0\0" /* reserved[0] */
851 "\0\0\0\0" /* reserved[1] */
852 ,16);
853 m4af_write16(ctx, track->num_channels);
854 m4af_write(ctx,
855 "\0\020" /* samplesize: 16 */
856 "\0\0" /* pre_defined */
857 "\0\0" /* reserved */
858 ,6);
859 if (track->codec == M4AF_FOURCC('m','p','4','a')) {
860 m4af_write32(ctx, track->timescale << 16);
861 m4af_write_esds_box(ctx, track_idx);
862 } else {
863 m4af_write32(ctx, 44100 << 16);
864 m4af_write_alac_box(ctx, track_idx);
865 }
866 m4af_update_box_size(ctx, pos);
867}
868
869static
870void m4af_write_stsd_box(m4af_ctx_t *ctx, uint32_t track_idx)
871{
872 int64_t pos = m4af_tell(ctx);
873 m4af_write(ctx, "\0\0\0\0stsd", 8);
874 m4af_write(ctx,
875 "\0" /* version */
876 "\0\0\0" /* flags */
877 "\0\0\0\001" /* entry_count: 1 */
878 , 8);
879 m4af_write_mp4a_box(ctx, track_idx);
880 m4af_update_box_size(ctx, pos);
881}
882
883static
884void m4af_write_sbgp_box(m4af_ctx_t *ctx, uint32_t track_idx)
885{
886 m4af_track_t *track = &ctx->track[track_idx];
887 m4af_write(ctx,
888 "\0\0\0\034" /* size: 28 */
889 "sbgp" /* type */
890 "\0" /* version */
891 "\0\0\0" /* flags */
892 "roll" /* grouping_type */
893 "\0\0\0\001" /* entry_count: 1 */
894 , 20);
895 m4af_write32(ctx, track->num_samples);
896 m4af_write32(ctx, 1); /* group_description_index */
897}
898
899static
900void m4af_write_sgpd_box(m4af_ctx_t *ctx, uint32_t track_idx)
901{
902 m4af_write(ctx,
903 "\0\0\0\026" /* size: 22 */
904 "sgpd" /* type */
905 "\0" /* version */
906 "\0\0\0" /* flags */
907 "roll" /* grouping_type */
908 "\0\0\0\001" /* entry_count: 1 */
909 "\377\377" /* payload_data: -1 */
910 , 22);
911}
912
913static
914void m4af_write_stbl_box(m4af_ctx_t *ctx, uint32_t track_idx)
915{
916 m4af_track_t *track = &ctx->track[track_idx];
917 int64_t pos = m4af_tell(ctx);
918 m4af_write(ctx, "\0\0\0\0stbl", 8);
919 m4af_write_stsd_box(ctx, track_idx);
920 if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) &&
921 (track->encoder_delay || track->padding)) {
922 m4af_write_sbgp_box(ctx, track_idx);
923 m4af_write_sgpd_box(ctx, track_idx);
924 }
925 m4af_write_stts_box(ctx, track_idx);
926 m4af_write_stsc_box(ctx, track_idx);
927 m4af_write_stsz_box(ctx, track_idx);
928 m4af_write_stco_box(ctx, track_idx);
929 m4af_update_box_size(ctx, pos);
930}
931
932static
933void m4af_write_url_box(m4af_ctx_t *ctx, uint32_t track_idx)
934{
935 m4af_write(ctx,
936 "\0\0\0\014" /* size */
937 "url " /* type */
938 "\0" /* version */
939 "\0\0\001" /* flags: 1(in the same file) */
940 , 12);
941}
942
943static
944void m4af_write_dref_box(m4af_ctx_t *ctx, uint32_t track_idx)
945{
946 int64_t pos = m4af_tell(ctx);
947 m4af_write(ctx, "\0\0\0\0dref", 8);
948 m4af_write(ctx,
949 "\0" /* version */
950 "\0\0\0" /* flags */
951 "\0\0\0\001" /* entry_count: 1 */
952 ,8);
953 m4af_write_url_box(ctx, track_idx);
954 m4af_update_box_size(ctx, pos);
955}
956
957static
958void m4af_write_dinf_box(m4af_ctx_t *ctx, uint32_t track_idx)
959{
960 int64_t pos = m4af_tell(ctx);
961 m4af_write(ctx, "\0\0\0\0dinf", 8);
962 m4af_write_dref_box(ctx, track_idx);
963 m4af_update_box_size(ctx, pos);
964}
965
966static
967void m4af_write_smhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
968{
969 m4af_write(ctx,
970 "\0\0\0\020" /* size */
971 "smhd" /* type */
972 "\0" /* version */
973 "\0\0\0" /* flags */
974 "\0\0" /* balance */
975 "\0\0" /* reserved */
976 , 16);
977}
978
979static
980void m4af_write_minf_box(m4af_ctx_t *ctx, uint32_t track_idx)
981{
982 m4af_track_t *track = &ctx->track[track_idx];
983 int64_t pos = m4af_tell(ctx);
984 m4af_write(ctx, "\0\0\0\0minf", 8);
985 /* TODO: add TEXT support */
986 if (track->codec != M4AF_CODEC_TEXT)
987 m4af_write_smhd_box(ctx, track_idx);
988 m4af_write_dinf_box(ctx, track_idx);
989 m4af_write_stbl_box(ctx, track_idx);
990 m4af_update_box_size(ctx, pos);
991}
992
993static
994void m4af_write_mdhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
995{
996 m4af_track_t *track = &ctx->track[track_idx];
997 int64_t pos = m4af_tell(ctx);
998 uint8_t version = (track->creation_time > UINT32_MAX ||
999 track->modification_time > UINT32_MAX ||
1000 track->duration > UINT32_MAX);
1001
1002 m4af_write(ctx, "\0\0\0\0mdhd", 8);
1003 m4af_write(ctx, &version, 1);
1004 m4af_write(ctx, "\0\0\0", 3); /* flags */
1005 if (version) {
1006 m4af_write64(ctx, track->creation_time);
1007 m4af_write64(ctx, track->modification_time);
1008 m4af_write32(ctx, track->timescale);
1009 m4af_write64(ctx, track->duration);
1010 } else {
1011 m4af_write32(ctx, track->creation_time);
1012 m4af_write32(ctx, track->modification_time);
1013 m4af_write32(ctx, track->timescale);
1014 m4af_write32(ctx, track->duration);
1015 }
1016 m4af_write(ctx,
1017 "\x55\xc4" /* language: und */
1018 "\0\0" /* pre_defined */
1019 , 4);
1020 m4af_update_box_size(ctx, pos);
1021}
1022
1023static
1024void m4af_write_hdlr_box(m4af_ctx_t *ctx, uint32_t track_idx, const char *type)
1025{
1026 int64_t pos = m4af_tell(ctx);
1027 static const char reserved_and_name[10] = { 0 };
1028
1029 m4af_write(ctx,
1030 "\0\0\0\0" /* size */
1031 "hdlr" /* type */
1032 "\0" /* version */
1033 "\0\0\0" /* flags */
1034 "\0\0\0\0" /* pre_defined */
1035 , 16);
1036 m4af_write(ctx, type, 4); /* handler_type */
1037 /* reserved[0] */
1038 m4af_write(ctx, !strcmp(type, "mdir") ? "appl" : "\0\0\0\0", 4);
1039 /* reserved[1], reserved[2], name */
1040 m4af_write(ctx, reserved_and_name, 9);
1041 m4af_update_box_size(ctx, pos);
1042}
1043
1044static
1045void m4af_write_mdia_box(m4af_ctx_t *ctx, uint32_t track_idx)
1046{
1047 m4af_track_t *track = &ctx->track[track_idx];
1048 const char *hdlr =
1049 (track->codec == M4AF_CODEC_TEXT) ? "text" : "soun";
1050 int64_t pos = m4af_tell(ctx);
1051 m4af_write(ctx, "\0\0\0\0mdia", 8);
1052 m4af_write_mdhd_box(ctx, track_idx);
1053 m4af_write_hdlr_box(ctx, track_idx, hdlr);
1054 m4af_write_minf_box(ctx, track_idx);
1055 m4af_update_box_size(ctx, pos);
1056}
1057
1058static
1059void m4af_write_elst_box(m4af_ctx_t *ctx, uint32_t track_idx)
1060{
1061 m4af_track_t *track = &ctx->track[track_idx];
1062 uint8_t version;
1063 int64_t duration = track->duration - track->encoder_delay - track->padding;
1064 int64_t pos = m4af_tell(ctx);
1065 duration = (double)duration / track->timescale * ctx->timescale + .5;
1066 version = (duration > UINT32_MAX);
1067
1068 m4af_write(ctx, "\0\0\0\0elst", 8);
1069 m4af_write(ctx, &version, 1);
1070 m4af_write(ctx, "\0\0\0", 3); /* flags */
1071 m4af_write32(ctx, 1); /* entry_count: 1 */
1072 if (version) {
1073 m4af_write64(ctx, duration);
1074 m4af_write64(ctx, track->encoder_delay);
1075 } else {
1076 m4af_write32(ctx, duration);
1077 m4af_write32(ctx, track->encoder_delay);
1078 }
1079 m4af_write16(ctx, 1); /* media_rate_integer */
1080 m4af_write16(ctx, 0); /* media_rate_fraction */
1081 m4af_update_box_size(ctx, pos);
1082}
1083
1084static
1085void m4af_write_edts_box(m4af_ctx_t *ctx, uint32_t track_idx)
1086{
1087 int64_t pos = m4af_tell(ctx);
1088 m4af_write(ctx, "\0\0\0\0edts", 8);
1089 m4af_write_elst_box(ctx, track_idx);
1090 m4af_update_box_size(ctx, pos);
1091}
1092
1093static
1094void m4af_write_tkhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
1095{
1096 m4af_track_t *track = &ctx->track[track_idx];
1097 int64_t pos = m4af_tell(ctx);
1098 int64_t duration =
1099 (double)track->duration / track->timescale * ctx->timescale + .5;
1100 uint8_t version = (track->creation_time > UINT32_MAX ||
1101 track->modification_time > UINT32_MAX ||
1102 duration > UINT32_MAX);
1103 m4af_write(ctx, "\0\0\0\0tkhd", 8);
1104 m4af_write(ctx, &version, 1);
1105 m4af_write(ctx, "\0\0\007", 3); /* flags */
1106 if (version) {
1107 m4af_write64(ctx, track->creation_time);
1108 m4af_write64(ctx, track->modification_time);
1109 m4af_write32(ctx, track_idx + 1);
1110 m4af_write(ctx, "\0\0\0\0" /* reserved */
1111 , 4);
1112 m4af_write64(ctx, duration);
1113 } else {
1114 m4af_write32(ctx, track->creation_time);
1115 m4af_write32(ctx, track->modification_time);
1116 m4af_write32(ctx, track_idx + 1);
1117 m4af_write(ctx, "\0\0\0\0" /* reserved */
1118 , 4);
1119 m4af_write32(ctx, duration);
1120 }
1121 m4af_write(ctx,
1122 "\0\0\0\0" /* reserved[0] */
1123 "\0\0\0\0" /* reserved[1] */
1124 "\0\0" /* layer */
1125 "\0\0" /* alternate_group */
1126 "\001\0" /* volume: 1.0 */
1127 "\0\0" /* reserved */
1128 "\0\001\0\0" /* matrix[0] */
1129 "\0\0\0\0" /* matrix[1] */
1130 "\0\0\0\0" /* matrix[2] */
1131 "\0\0\0\0" /* matrix[3] */
1132 "\0\001\0\0" /* matrix[4] */
1133 "\0\0\0\0" /* matrix[5] */
1134 "\0\0\0\0" /* matrix[6] */
1135 "\0\0\0\0" /* matrix[7] */
1136 "\100\0\0\0" /* matrix[8] */
1137 "\0\0\0\0" /* width */
1138 "\0\0\0\0" /* height */
1139 , 60);
1140 m4af_update_box_size(ctx, pos);
1141}
1142
1143static
1144void m4af_write_trak_box(m4af_ctx_t *ctx, uint32_t track_idx)
1145{
1146 m4af_track_t *track = &ctx->track[track_idx];
1147 int64_t pos = m4af_tell(ctx);
1148 m4af_write(ctx, "\0\0\0\0trak", 8);
1149 m4af_write_tkhd_box(ctx, track_idx);
1150 if ((ctx->priming_mode & M4AF_PRIMING_MODE_EDTS) &&
1151 (track->encoder_delay || track->padding))
1152 m4af_write_edts_box(ctx, track_idx);
1153 m4af_write_mdia_box(ctx, track_idx);
1154 m4af_update_box_size(ctx, pos);
1155}
1156
1157static
1158int64_t m4af_movie_duration(m4af_ctx_t *ctx)
1159{
1160 int64_t movie_duration = 0;
1161 unsigned i;
1162 for (i = 0; i < ctx->num_tracks; ++i) {
1163 double x = ctx->track[i].duration;
1164 int64_t duration = x / ctx->track[i].timescale * ctx->timescale + .5;
1165 if (duration > movie_duration)
1166 movie_duration = duration;
1167 }
1168 return movie_duration;
1169}
1170
1171static
1172void m4af_write_mvhd_box(m4af_ctx_t *ctx)
1173{
1174 int64_t pos = m4af_tell(ctx);
1175 int64_t movie_duration = m4af_movie_duration(ctx);
1176 uint8_t version = (ctx->creation_time > UINT32_MAX ||
1177 ctx->modification_time > UINT32_MAX ||
1178 movie_duration > UINT32_MAX);
1179
1180 m4af_write(ctx, "\0\0\0\0mvhd", 8);
1181 m4af_write(ctx, &version, 1);
1182 m4af_write(ctx, "\0\0\0", 3); /* flags */
1183 if (version) {
1184 m4af_write64(ctx, ctx->creation_time);
1185 m4af_write64(ctx, ctx->modification_time);
1186 m4af_write32(ctx, ctx->timescale);
1187 m4af_write64(ctx, movie_duration);
1188 } else {
1189 m4af_write32(ctx, ctx->creation_time);
1190 m4af_write32(ctx, ctx->modification_time);
1191 m4af_write32(ctx, ctx->timescale);
1192 m4af_write32(ctx, movie_duration);
1193 }
1194 m4af_write(ctx,
1195 "\0\001\0\0" /* rate: 1.0 */
1196 "\001\0" /* volume: 1.0 */
1197 "\0\0" /* reserved */
1198 "\0\0\0\0" /* reserved[0] */
1199 "\0\0\0\0" /* reserved[1] */
1200 "\0\001\0\0" /* matrix[0] */
1201 "\0\0\0\0" /* matrix[1] */
1202 "\0\0\0\0" /* matrix[2] */
1203 "\0\0\0\0" /* matrix[3] */
1204 "\0\001\0\0" /* matrix[4] */
1205 "\0\0\0\0" /* matrix[5] */
1206 "\0\0\0\0" /* matrix[6] */
1207 "\0\0\0\0" /* matrix[7] */
1208 "\100\0\0\0" /* matrix[8] */
1209 "\0\0\0\0" /* pre_defined[0] */
1210 "\0\0\0\0" /* pre_defined[1] */
1211 "\0\0\0\0" /* pre_defined[2] */
1212 "\0\0\0\0" /* pre_defined[3] */
1213 "\0\0\0\0" /* pre_defined[4] */
1214 "\0\0\0\0" /* pre_defined[5] */
1215 , 76);
1216 m4af_write32(ctx, ctx->num_tracks + 1);
1217 m4af_update_box_size(ctx, pos);
1218}
1219
1220static
1221void m4af_write_mean_box(m4af_ctx_t *ctx)
1222{
1223 m4af_write(ctx,
1224 "\0\0\0\034" /* size */
1225 "mean"
1226 "\0" /* version */
1227 "\0\0\0" /* flags */
1228 "com.apple.iTunes" /* meaning-string */
1229 , 28);
1230}
1231
1232static
1233void m4af_write_name_box(m4af_ctx_t *ctx, const char *name)
1234{
1235 int64_t pos = m4af_tell(ctx);
1236 m4af_write(ctx,
1237 "\0\0\0\0" /* size */
1238 "name" /* type */
1239 "\0" /* version */
1240 "\0\0\0" /* flags */
1241 , 12);
1242 m4af_write(ctx, name, strlen(name));
1243 m4af_update_box_size(ctx, pos);
1244}
1245
1246static
1247void m4af_write_data_box(m4af_ctx_t *ctx, uint32_t type_code,
1248 const char *data, uint32_t data_size)
1249{
1250 int64_t pos = m4af_tell(ctx);
1251 uint8_t code = type_code;
1252 m4af_write(ctx,
1253 "\0\0\0\0" /* size */
1254 "data" /* type */
1255 "\0\0" /* reserved */
1256 "\0" /* type_set_indifier */
1257 ,11);
1258 m4af_write(ctx, &code, 1);
1259 m4af_write(ctx, "\0\0\0\0", 4); /* locale */
1260 m4af_write(ctx, data, data_size);
1261 m4af_update_box_size(ctx, pos);
1262}
1263
1264static
1265void m4af_write_metadata(m4af_ctx_t *ctx, m4af_itmf_entry_t *entry)
1266{
1267 int64_t pos = m4af_tell(ctx);
1268 m4af_write(ctx, "\0\0\0\0", 4);
1269 m4af_write32(ctx, entry->fcc);
1270 if (entry->fcc != M4AF_FOURCC('-','-','-','-'))
1271 m4af_write_data_box(ctx, entry->type_code,
1272 entry->data, entry->data_size);
1273 else {
1274 m4af_write_mean_box(ctx);
1275 m4af_write_name_box(ctx, entry->name);
1276 m4af_write_data_box(ctx, 1, entry->data, entry->data_size);
1277 }
1278 m4af_update_box_size(ctx, pos);
1279}
1280
1281static
1282void m4af_write_ilst_box(m4af_ctx_t *ctx)
1283{
1284 uint32_t i;
1285 int64_t pos = m4af_tell(ctx);
1286 m4af_write(ctx, "\0\0\0\0ilst", 8);
1287 for (i = 0; i < ctx->num_tags; ++i)
1288 m4af_write_metadata(ctx, &ctx->itmf_table[i]);
1289 m4af_update_box_size(ctx, pos);
1290}
1291
1292static
1293void m4af_write_meta_box(m4af_ctx_t *ctx)
1294{
1295 int64_t pos = m4af_tell(ctx);
1296 m4af_write(ctx,
1297 "\0\0\0\0" /* size */
1298 "meta" /* type */
1299 "\0" /* version */
1300 "\0\0\0" /* flags */
1301 , 12);
1302 m4af_write_hdlr_box(ctx, 0, "mdir");
1303 m4af_write_ilst_box(ctx);
1304 m4af_update_box_size(ctx, pos);
1305}
1306
1307static
1308void m4af_write_udta_box(m4af_ctx_t *ctx)
1309{
1310 int64_t pos = m4af_tell(ctx);
1311 m4af_write(ctx, "\0\0\0\0udta", 8);
1312 m4af_write_meta_box(ctx);
1313 m4af_update_box_size(ctx, pos);
1314}
1315
1316static
1317uint32_t m4af_write_moov_box(m4af_ctx_t *ctx)
1318{
1319 unsigned i;
1320 int64_t pos = m4af_tell(ctx);
1321 m4af_write(ctx, "\0\0\0\0moov", 8);
1322 m4af_write_mvhd_box(ctx);
1323 for (i = 0; i < ctx->num_tracks; ++i)
1324 m4af_write_trak_box(ctx, i);
1325 if (ctx->num_tags)
1326 m4af_write_udta_box(ctx);
1327 return m4af_update_box_size(ctx, pos);
1328}
1329
1330static
1331void m4af_finalize_mdat(m4af_ctx_t *ctx)
1332{
1333 if (ctx->mdat_size + 8 > UINT32_MAX) {
1334 m4af_set_pos(ctx, ctx->mdat_pos - 16);
1335 m4af_write32(ctx, 1);
1336 m4af_write(ctx, "mdat", 4);
1337 m4af_write64(ctx, ctx->mdat_size + 16);
1338 } else {
1339 m4af_set_pos(ctx, ctx->mdat_pos - 8);
1340 m4af_write32(ctx, ctx->mdat_size + 8);
1341 }
1342 m4af_set_pos(ctx, ctx->mdat_pos + ctx->mdat_size);
1343}
1344
1345static
1346uint64_t m4af_patch_moov(m4af_ctx_t *ctx, uint32_t moov_size, uint32_t offset)
1347{
1348 int64_t pos = 0;
1349 uint32_t moov_size2;
1350 int i, j;
1351 m4af_io_callbacks_t io_reserve = ctx->io;
1352 void *io_cookie_reserve = ctx->io_cookie;
1353
1354 for (i = 0; i < ctx->num_tracks; ++i)
1355 for (j = 0; j < ctx->track[i].num_chunks; ++j)
1356 ctx->track[i].chunk_table[j].offset += offset;
1357
1358 ctx->io = m4af_null_io_callbacks;
1359 ctx->io_cookie = &pos;
1360 moov_size2 = m4af_write_moov_box(ctx);
1361
1362 if (moov_size2 != moov_size) {
1363 /* stco -> co64 switching */
1364 for (i = 0; i < ctx->num_tracks; ++i)
1365 for (j = 0; j < ctx->track[i].num_chunks; ++j)
1366 ctx->track[i].chunk_table[j].offset += moov_size2 - moov_size;
1367 moov_size2 = m4af_write_moov_box(ctx);
1368 }
1369 ctx->io = io_reserve;
1370 ctx->io_cookie = io_cookie_reserve;
1371 return moov_size2;
1372}
1373
1374static
1375void m4af_shift_mdat_pos(m4af_ctx_t *ctx, uint32_t offset)
1376{
1377 unsigned i, j;
1378 int64_t begin, end;
1379 char *buf;
1380
1381 buf = malloc(1024*1024*2);
1382
1383 end = ctx->mdat_pos + ctx->mdat_size;
1384 for (; (begin = m4af_max(ctx->mdat_pos, end - 1024*1024*2)) < end;
1385 end = begin) {
1386 m4af_set_pos(ctx, begin);
1387 ctx->io.read(ctx->io_cookie, buf, end - begin);
1388 m4af_set_pos(ctx, begin + offset);
1389 m4af_write(ctx, buf, end - begin);
1390 }
1391 ctx->mdat_pos += offset;
1392 m4af_set_pos(ctx, ctx->mdat_pos - 16);
1393 m4af_write_free_box(ctx, 0);
1394 m4af_write(ctx, "\0\0\0\0mdat", 8);
1395 m4af_finalize_mdat(ctx);
1396
1397 free(buf);
1398}
1399
1400int m4af_finalize(m4af_ctx_t *ctx, int optimize)
1401{
1402 unsigned i;
1403 m4af_track_t *track;
1404 uint32_t moov_size;
1405
1406 for (i = 0; i < ctx->num_tracks; ++i) {
1407 track = ctx->track + i;
1408 if (track->duration) {
1409 int64_t track_size = 0;
1410 unsigned j;
1411 for (j = 0; j < track->num_chunks; ++j)
1412 track_size += track->chunk_table[j].size;
1413 track->avgBitrate =
1414 8.0 * track_size * track->timescale / track->duration + .5;
1415 }
1416 m4af_flush_chunk(ctx, i);
1417 }
1418 track = ctx->track;
1419 if ((ctx->priming_mode & M4AF_PRIMING_MODE_ITUNSMPB) &&
1420 (track->encoder_delay || track->padding))
1421 m4af_set_iTunSMPB(ctx);
1422 m4af_finalize_mdat(ctx);
1423 moov_size = m4af_write_moov_box(ctx);
1424 if (optimize) {
1425 int64_t pos;
1426 uint32_t moov_size2 = m4af_patch_moov(ctx, moov_size, moov_size + 1024);
1427 m4af_shift_mdat_pos(ctx, moov_size2 + 1024);
1428 m4af_set_pos(ctx, 32);
1429 m4af_write_moov_box(ctx);
1430 pos = m4af_tell(ctx);
1431 m4af_write_free_box(ctx, ctx->mdat_pos - pos - 24);
1432 }
1433 return ctx->last_error;
1434}
This page took 0.038657 seconds and 4 git commands to generate.