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