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