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