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