]> iEval git - fdkaac.git/blame - src/m4af.c
m4af: duplication check on adding tags
[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
93fb917b 429m4af_itmf_entry_t *m4af_find_itmf_slot(m4af_ctx_t *ctx, uint32_t fcc,
430 const char *name)
48e2f01c 431{
93fb917b 432 m4af_itmf_entry_t *entry = ctx->itmf_table;
433
434 if (name)
435 fcc = M4AF_FOURCC('-','-','-','-');
436
437 if (fcc != M4AF_TAG_ARTWORK)
438 for (; entry != ctx->itmf_table + ctx->num_tags; ++entry)
439 if (fcc == entry->fcc && (!name || !strcmp(name, entry->name)))
440 return entry;
441
48e2f01c 442 if (ctx->num_tags == ctx->itmf_table_capacity) {
443 uint32_t new_size = ctx->itmf_table_capacity;
444 new_size = new_size ? new_size * 2 : 1;
445 entry = m4af_realloc(ctx->itmf_table, new_size * sizeof(*entry));
446 if (entry == 0) {
447 ctx->last_error = M4AF_NO_MEMORY;
93fb917b 448 return 0;
48e2f01c 449 }
450 ctx->itmf_table = entry;
451 ctx->itmf_table_capacity = new_size;
452 }
93fb917b 453 entry = &ctx->itmf_table[ctx->num_tags++];
454 memset(entry, 0, sizeof(m4af_itmf_entry_t));
455 entry->fcc = fcc;
456 if (name) {
457 char *name_copy = m4af_realloc(0, strlen(name) + 1);
458 if (!name_copy) {
459 ctx->last_error = M4AF_NO_MEMORY;
460 --ctx->num_tags;
461 return 0;
462 }
463 strcpy(name_copy, name);
464 entry->name = name_copy;
465 }
466 return entry;
48e2f01c 467}
468
e4bbeeb0 469int m4af_add_itmf_long_tag(m4af_ctx_t *ctx, const char *name,
48e2f01c 470 const char *data)
471{
472 m4af_itmf_entry_t *entry;
93fb917b 473 char *data_copy = 0;
48e2f01c 474 size_t name_len = strlen(name);
475 size_t data_len = strlen(data);
93fb917b 476 if (!name_len || !data_len)
477 return 0;
478
479 if ((entry = m4af_find_itmf_slot(ctx, 0, name)) == 0)
480 goto FAIL;
481 entry->type_code = M4AF_UTF8;
482 if ((data_copy = m4af_realloc(entry->data, data_len)) == 0) {
48e2f01c 483 ctx->last_error = M4AF_NO_MEMORY;
484 goto FAIL;
485 }
48e2f01c 486 memcpy(data_copy, data, data_len);
48e2f01c 487 entry->data = data_copy;
488 entry->data_size = data_len;
489 return 0;
490FAIL:
e4bbeeb0 491 return ctx->last_error;
48e2f01c 492}
493
e4bbeeb0 494int m4af_add_itmf_short_tag(m4af_ctx_t *ctx, uint32_t fcc,
48e2f01c 495 uint32_t type_code, const void *data,
496 uint32_t data_size)
497{
498 m4af_itmf_entry_t *entry;
93fb917b 499 char *data_copy = 0;
500
501 if (!data_size)
502 return 0;
503 if ((entry = m4af_find_itmf_slot(ctx, fcc, 0)) == 0)
504 goto FAIL;
505 entry->type_code = type_code;
506 if ((data_copy = m4af_realloc(entry->data, data_size)) == 0) {
48e2f01c 507 ctx->last_error = M4AF_NO_MEMORY;
508 goto FAIL;
509 }
48e2f01c 510 memcpy(data_copy, data, data_size);
511 entry->data = data_copy;
512 entry->data_size = data_size;
513 return 0;
514FAIL:
e4bbeeb0 515 return ctx->last_error;
48e2f01c 516}
517
e4bbeeb0 518int m4af_add_itmf_string_tag(m4af_ctx_t *ctx, uint32_t fcc, const char *data)
48e2f01c 519{
e4bbeeb0 520 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_UTF8, data, strlen(data));
48e2f01c 521}
522
e4bbeeb0 523int m4af_add_itmf_int8_tag(m4af_ctx_t *ctx, uint32_t fcc, int value)
48e2f01c 524{
525 uint8_t data = value;
e4bbeeb0 526 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 1);
48e2f01c 527}
528
e4bbeeb0 529int m4af_add_itmf_int16_tag(m4af_ctx_t *ctx, uint32_t fcc, int value)
48e2f01c 530{
531 uint16_t data = m4af_htob16(value);
e4bbeeb0 532 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 2);
48e2f01c 533}
534
e4bbeeb0 535int m4af_add_itmf_int32_tag(m4af_ctx_t *ctx, uint32_t fcc, uint32_t value)
48e2f01c 536{
537 uint32_t data = m4af_htob32(value);
e4bbeeb0 538 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 4);
48e2f01c 539}
540
e4bbeeb0 541int m4af_add_itmf_int64_tag(m4af_ctx_t *ctx, uint32_t fcc, uint64_t value)
c5c45908 542{
543 uint64_t data = m4af_htob64(value);
e4bbeeb0 544 return m4af_add_itmf_short_tag(ctx, fcc, M4AF_INTEGER, &data, 8);
c5c45908 545}
546
e4bbeeb0 547int m4af_add_itmf_track_tag(m4af_ctx_t *ctx, int track, int total)
48e2f01c 548{
549 uint16_t data[4] = { 0 };
550 data[1] = m4af_htob16(track);
551 data[2] = m4af_htob16(total);
552 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('t','r','k','n'),
553 M4AF_IMPLICIT, &data, 8);
554}
555
e4bbeeb0 556int m4af_add_itmf_disk_tag(m4af_ctx_t *ctx, int disk, int total)
48e2f01c 557{
558 uint16_t data[3] = { 0 };
559 data[1] = m4af_htob16(disk);
560 data[2] = m4af_htob16(total);
561 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('d','i','s','k'),
562 M4AF_IMPLICIT, &data, 6);
563}
564
e4bbeeb0 565int m4af_add_itmf_genre_tag(m4af_ctx_t *ctx, int genre)
48e2f01c 566{
567 uint16_t data = m4af_htob16(genre);
568 return m4af_add_itmf_short_tag(ctx, M4AF_FOURCC('g','n','r','e'),
569 M4AF_IMPLICIT, &data, 2);
570}
571
572static
e4bbeeb0 573int m4af_set_iTunSMPB(m4af_ctx_t *ctx)
48e2f01c 574{
e4bbeeb0 575 const char *fmt = " 00000000 %08X %08X %08X%08X 00000000 00000000 "
48e2f01c 576 "00000000 00000000 00000000 00000000 00000000 00000000";
577 m4af_track_t *track = &ctx->track[0];
578 char buf[256];
579 uint64_t length = track->duration - track->encoder_delay - track->padding;
e4bbeeb0 580 sprintf(buf, fmt, track->encoder_delay, track->padding,
48e2f01c 581 (uint32_t)(length >> 32), (uint32_t)length);
582 return m4af_add_itmf_long_tag(ctx, "iTunSMPB", buf);
583}
584
585static
e4bbeeb0 586void m4af_update_box_size(m4af_ctx_t *ctx, int64_t pos)
48e2f01c 587{
588 int64_t current_pos = m4af_tell(ctx);
589 m4af_set_pos(ctx, pos);
590 m4af_write32(ctx, current_pos - pos);
591 m4af_set_pos(ctx, current_pos);
592}
593
48e2f01c 594static
e4bbeeb0 595void m4af_write_descriptor(m4af_ctx_t *ctx, uint32_t tag, uint32_t size)
48e2f01c 596{
597 uint8_t buf[5];
598 buf[0] = tag;
599 buf[1] = ((size >> 21) | 0x80);
600 buf[2] = ((size >> 14) | 0x80);
601 buf[3] = ((size >> 7) | 0x80);
602 buf[4] = (size & 0x7f);
603 m4af_write(ctx, buf, 5);
604}
605
606static
e4bbeeb0 607void m4af_write_ftyp_box(m4af_ctx_t *ctx)
48e2f01c 608{
609 m4af_write(ctx, "\0\0\0\040""ftypM4A \0\0\0\0M4A mp42isom\0\0\0\0", 32);
610}
611
612static
e4bbeeb0 613void m4af_write_free_box(m4af_ctx_t *ctx, uint32_t size)
48e2f01c 614{
615 int64_t pos = m4af_tell(ctx);
616 m4af_write32(ctx, size + 8);
617 m4af_write(ctx, "free", 4);
618 if (size > 0)
619 m4af_set_pos(ctx, pos + size + 8);
620}
621
e4bbeeb0 622int m4af_begin_write(m4af_ctx_t *ctx)
48e2f01c 623{
e4bbeeb0 624 m4af_write_ftyp_box(ctx);
625 m4af_write_free_box(ctx, 0);
48e2f01c 626 m4af_write(ctx, "\0\0\0\0mdat", 8);
627 ctx->mdat_pos = m4af_tell(ctx);
e4bbeeb0 628 return ctx->last_error;
48e2f01c 629}
630
631static
e4bbeeb0 632void m4af_write_stco_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 633{
634 m4af_track_t *track = &ctx->track[track_idx];
635 uint32_t i;
636 m4af_chunk_entry_t *index = track->chunk_table;
637 int is_co64 = (ctx->mdat_pos + ctx->mdat_size > UINT32_MAX);
638 int64_t pos = m4af_tell(ctx);
639
640 m4af_write32(ctx, 0); /* size */
641 m4af_write(ctx, is_co64 ? "co64" : "stco", 4);
642 m4af_write32(ctx, 0); /* version and flags */
643 m4af_write32(ctx, track->num_chunks);
644 for (i = 0; i < track->num_chunks; ++i, ++index) {
645 if (is_co64)
646 m4af_write64(ctx, index->offset);
647 else
648 m4af_write32(ctx, index->offset);
649 }
e4bbeeb0 650 m4af_update_box_size(ctx, pos);
48e2f01c 651}
652
653static
e4bbeeb0 654void m4af_write_stsz_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 655{
656 m4af_track_t *track = &ctx->track[track_idx];
657 m4af_sample_entry_t *index = track->sample_table;
658 uint32_t i;
659 int64_t pos = m4af_tell(ctx);
660 m4af_write(ctx,
661 "\0\0\0\0" /* size */
662 "stsz" /* type */
663 "\0" /* version */
664 "\0\0\0" /* flags */
665 "\0\0\0\0" /* sample_size: 0(variable) */
666 , 16);
667 m4af_write32(ctx, track->num_samples);
668 for (i = 0; i < track->num_samples; ++i, ++index)
669 m4af_write32(ctx, index->size);
e4bbeeb0 670 m4af_update_box_size(ctx, pos);
48e2f01c 671}
672
673static
e4bbeeb0 674void m4af_write_stsc_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 675{
676 m4af_track_t *track = &ctx->track[track_idx];
677 m4af_chunk_entry_t *index = track->chunk_table;
678 uint32_t i, prev_samples_per_chunk = 0, entry_count = 0;
679 int64_t pos = m4af_tell(ctx);
680 m4af_write(ctx,
681 "\0\0\0\0" /* size */
682 "stsc" /* type */
683 "\0" /* version */
684 "\0\0\0" /* flags */
685 "\0\0\0\0" /* entry_count */
686 , 16);
687
688 for (i = 0; i < track->num_chunks; ++i, ++index) {
689 if (index->samples_per_chunk != prev_samples_per_chunk) {
690 ++entry_count;
691 m4af_write32(ctx, i + 1);
692 m4af_write32(ctx, index->samples_per_chunk);
693 m4af_write32(ctx, 1); /* sample_description_index */
694 prev_samples_per_chunk = index->samples_per_chunk;
695 }
696 }
697 m4af_write32_at(ctx, pos + 12, entry_count);
e4bbeeb0 698 m4af_update_box_size(ctx, pos);
48e2f01c 699}
700
701static
e4bbeeb0 702void m4af_write_stts_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 703{
704 m4af_track_t *track = &ctx->track[track_idx];
705 m4af_sample_entry_t *index = track->sample_table;
706 uint32_t i, prev_delta = 0, entry_count = 0, sample_count = 0;
707 int64_t pos = m4af_tell(ctx);
708 m4af_write(ctx,
709 "\0\0\0\0" /* size */
710 "stts" /* type */
711 "\0" /* version */
712 "\0\0\0" /* flags */
713 "\0\0\0\0" /* entry_count */
714 , 16);
715
716 for (i = 0; i < track->num_samples; ++i, ++index) {
717 if (index->delta == prev_delta)
718 ++sample_count;
719 else {
720 ++entry_count;
721 if (sample_count) {
722 m4af_write32(ctx, sample_count);
723 m4af_write32(ctx, prev_delta);
724 }
725 prev_delta = index->delta;
726 sample_count = 1;
727 }
728 }
729 if (sample_count) {
730 m4af_write32(ctx, sample_count);
731 m4af_write32(ctx, prev_delta);
732 }
733 m4af_write32_at(ctx, pos + 12, entry_count);
e4bbeeb0 734 m4af_update_box_size(ctx, pos);
48e2f01c 735}
736
737static
e4bbeeb0 738void m4af_write_esds_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 739{
740 m4af_track_t *track = &ctx->track[track_idx];
741 int64_t pos = m4af_tell(ctx);
742 m4af_write(ctx, "\0\0\0\0esds", 8);
743 m4af_write32(ctx, 0); /* version + flags */
744
745 /* ES_Descriptor */
e4bbeeb0 746 m4af_write_descriptor(ctx, 3, 32 + track->decSpecificInfoSize);
48e2f01c 747 m4af_write(ctx, "\0\0\0", 3);
748 /* DecoderConfigDescriptor */
e4bbeeb0 749 m4af_write_descriptor(ctx, 4, 18 + track->decSpecificInfoSize);
48e2f01c 750 m4af_write(ctx,
751 "\x40" /* objectTypeIndication: 0x40(Audio ISO/IEC 14496-3)*/
752 "\x15" /* streamType(6): 0x05(AudioStream)
753 * upStream(1) : 0
754 * reserved(1) : 1
755 */
756 , 2);
757 m4af_write24(ctx, track->bufferSizeDB);
758 m4af_write32(ctx, track->maxBitrate);
759 m4af_write32(ctx, track->avgBitrate);
760 /* DecoderSpecificInfo */
e4bbeeb0 761 m4af_write_descriptor(ctx, 5, track->decSpecificInfoSize);
48e2f01c 762 m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize);
763 /* SLConfigDescriptor */
e4bbeeb0 764 m4af_write_descriptor(ctx, 6, 1);
48e2f01c 765 m4af_write(ctx, "\002", 1); /* predefined */
766
e4bbeeb0 767 m4af_update_box_size(ctx, pos);
48e2f01c 768}
769
770static
e4bbeeb0 771void m4af_write_alac_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 772{
773 m4af_track_t *track = &ctx->track[track_idx];
774 int64_t pos = m4af_tell(ctx);
775 m4af_write(ctx,
776 "\0\0\0\0" /* size */
777 "alac" /* type */
778 "\0" /* version */
779 "\0\0\0" /* flags */
780 , 12);
781 m4af_write(ctx, track->decSpecificInfo, track->decSpecificInfoSize);
e4bbeeb0 782 m4af_update_box_size(ctx, pos);
48e2f01c 783}
784
785static
e4bbeeb0 786void m4af_write_mp4a_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 787{
788 m4af_track_t *track = &ctx->track[track_idx];
789 int64_t pos = m4af_tell(ctx);
790 m4af_write32(ctx, 0); /* size */
791 m4af_write32(ctx, track->codec); /* mp4a or alac */
792 m4af_write(ctx,
793 "\0\0\0\0\0\0" /* reserved */
794 "\0\001" /* data_reference_index: 1 */
795 "\0\0\0\0" /* reserved[0] */
796 "\0\0\0\0" /* reserved[1] */
797 "\0\002" /* channelcount: 2 */
798 "\0\020" /* samplesize: 16 */
799 "\0\0" /* pre_defined */
800 "\0\0" /* reserved */
801 ,24);
802 if (track->codec == M4AF_FOURCC('m','p','4','a')) {
803 m4af_write32(ctx, track->timescale << 16);
e4bbeeb0 804 m4af_write_esds_box(ctx, track_idx);
48e2f01c 805 } else {
e4bbeeb0 806 m4af_write32(ctx, 44100 << 16);
807 m4af_write_alac_box(ctx, track_idx);
48e2f01c 808 }
e4bbeeb0 809 m4af_update_box_size(ctx, pos);
48e2f01c 810}
811
812static
e4bbeeb0 813void m4af_write_stsd_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\0stsd", 8);
817 m4af_write(ctx,
818 "\0" /* version */
819 "\0\0\0" /* flags */
820 "\0\0\0\001" /* entry_count: 1 */
821 , 8);
e4bbeeb0 822 m4af_write_mp4a_box(ctx, track_idx);
823 m4af_update_box_size(ctx, pos);
48e2f01c 824}
825
826static
e4bbeeb0 827void m4af_write_stbl_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 828{
829 int64_t pos = m4af_tell(ctx);
830 m4af_write(ctx, "\0\0\0\0stbl", 8);
e4bbeeb0 831 m4af_write_stsd_box(ctx, track_idx);
832 m4af_write_stts_box(ctx, track_idx);
833 m4af_write_stsc_box(ctx, track_idx);
834 m4af_write_stsz_box(ctx, track_idx);
835 m4af_write_stco_box(ctx, track_idx);
836 m4af_update_box_size(ctx, pos);
48e2f01c 837}
838
839static
e4bbeeb0 840void m4af_write_url_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 841{
842 m4af_write(ctx,
843 "\0\0\0\014" /* size */
844 "url " /* type */
845 "\0" /* version */
846 "\0\0\001" /* flags: 1(in the same file) */
847 , 12);
848}
849
850static
e4bbeeb0 851void m4af_write_dref_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\0dref", 8);
855 m4af_write(ctx,
856 "\0" /* version */
857 "\0\0\0" /* flags */
858 "\0\0\0\001" /* entry_count: 1 */
859 ,8);
e4bbeeb0 860 m4af_write_url_box(ctx, track_idx);
861 m4af_update_box_size(ctx, pos);
48e2f01c 862}
863
864static
e4bbeeb0 865void m4af_write_dinf_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 866{
867 int64_t pos = m4af_tell(ctx);
868 m4af_write(ctx, "\0\0\0\0dinf", 8);
e4bbeeb0 869 m4af_write_dref_box(ctx, track_idx);
870 m4af_update_box_size(ctx, pos);
48e2f01c 871}
872
873static
e4bbeeb0 874void m4af_write_smhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 875{
876 m4af_write(ctx,
877 "\0\0\0\020" /* size */
878 "smhd" /* type */
879 "\0" /* version */
880 "\0\0\0" /* flags */
881 "\0\0" /* balance */
882 "\0\0" /* reserved */
883 , 16);
884}
885
886static
e4bbeeb0 887void m4af_write_minf_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);
891 m4af_write(ctx, "\0\0\0\0minf", 8);
892 /* TODO: add TEXT support */
893 if (track->codec != M4AF_CODEC_TEXT)
e4bbeeb0 894 m4af_write_smhd_box(ctx, track_idx);
895 m4af_write_dinf_box(ctx, track_idx);
896 m4af_write_stbl_box(ctx, track_idx);
897 m4af_update_box_size(ctx, pos);
48e2f01c 898}
899
900static
e4bbeeb0 901void m4af_write_mdhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 902{
903 m4af_track_t *track = &ctx->track[track_idx];
904 int64_t pos = m4af_tell(ctx);
f67cfe22 905 uint8_t version = (track->creation_time > UINT32_MAX ||
906 track->modification_time > UINT32_MAX ||
907 track->duration > UINT32_MAX);
48e2f01c 908
909 m4af_write(ctx, "\0\0\0\0mdhd", 8);
910 m4af_write(ctx, &version, 1);
911 m4af_write(ctx, "\0\0\0", 3); /* flags */
912 if (version) {
913 m4af_write64(ctx, track->creation_time);
914 m4af_write64(ctx, track->modification_time);
915 m4af_write32(ctx, track->timescale);
916 m4af_write64(ctx, track->duration);
917 } else {
918 m4af_write32(ctx, track->creation_time);
919 m4af_write32(ctx, track->modification_time);
920 m4af_write32(ctx, track->timescale);
921 m4af_write32(ctx, track->duration);
922 }
923 m4af_write(ctx,
924 "\x55\xc4" /* language: und */
925 "\0\0" /* pre_defined */
926 , 4);
e4bbeeb0 927 m4af_update_box_size(ctx, pos);
48e2f01c 928}
929
930static
e4bbeeb0 931void m4af_write_hdlr_box(m4af_ctx_t *ctx, uint32_t track_idx, const char *type)
48e2f01c 932{
933 int64_t pos = m4af_tell(ctx);
934 static const char reserved_and_name[10] = { 0 };
935
936 m4af_write(ctx,
937 "\0\0\0\0" /* size */
938 "hdlr" /* type */
939 "\0" /* version */
940 "\0\0\0" /* flags */
941 "\0\0\0\0" /* pre_defined */
942 , 16);
943 m4af_write(ctx, type, 4); /* handler_type */
944 /* reserved[0] */
945 m4af_write(ctx, !strcmp(type, "mdir") ? "appl" : "\0\0\0\0", 4);
946 /* reserved[1], reserved[2], name */
947 m4af_write(ctx, reserved_and_name, (pos & 1) ? 9 : 10);
e4bbeeb0 948 m4af_update_box_size(ctx, pos);
48e2f01c 949}
950
951static
e4bbeeb0 952void m4af_write_mdia_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 953{
954 m4af_track_t *track = &ctx->track[track_idx];
955 const char *hdlr =
956 (track->codec == M4AF_CODEC_TEXT) ? "text" : "soun";
957 int64_t pos = m4af_tell(ctx);
958 m4af_write(ctx, "\0\0\0\0mdia", 8);
e4bbeeb0 959 m4af_write_mdhd_box(ctx, track_idx);
960 m4af_write_hdlr_box(ctx, track_idx, hdlr);
961 m4af_write_minf_box(ctx, track_idx);
962 m4af_update_box_size(ctx, pos);
48e2f01c 963}
964
965static
e4bbeeb0 966void m4af_write_tkhd_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 967{
968 m4af_track_t *track = &ctx->track[track_idx];
969 int64_t pos = m4af_tell(ctx);
f67cfe22 970 int64_t duration =
971 (double)track->duration / track->timescale * ctx->timescale + .5;
972 uint8_t version = (track->creation_time > UINT32_MAX ||
973 track->modification_time > UINT32_MAX ||
974 duration > UINT32_MAX);
48e2f01c 975 m4af_write(ctx, "\0\0\0\0tkhd", 8);
976 m4af_write(ctx, &version, 1);
977 m4af_write(ctx, "\0\0\007", 3); /* flags */
978 if (version) {
979 m4af_write64(ctx, track->creation_time);
980 m4af_write64(ctx, track->modification_time);
981 m4af_write32(ctx, track_idx + 1);
982 m4af_write(ctx, "\0\0\0\0" /* reserved */
983 , 4);
f67cfe22 984 m4af_write64(ctx, duration);
48e2f01c 985 } else {
986 m4af_write32(ctx, track->creation_time);
987 m4af_write32(ctx, track->modification_time);
988 m4af_write32(ctx, track_idx + 1);
989 m4af_write(ctx, "\0\0\0\0" /* reserved */
990 , 4);
f67cfe22 991 m4af_write32(ctx, duration);
48e2f01c 992 }
993 m4af_write(ctx,
994 "\0\0\0\0" /* reserved[0] */
995 "\0\0\0\0" /* reserved[1] */
996 "\0\0" /* layer */
997 "\0\0" /* alternate_group */
998 "\001\0" /* volume: 1.0 */
999 "\0\0" /* reserved */
1000 "\0\001\0\0" /* matrix[0] */
1001 "\0\0\0\0" /* matrix[1] */
1002 "\0\0\0\0" /* matrix[2] */
1003 "\0\0\0\0" /* matrix[3] */
1004 "\0\001\0\0" /* matrix[4] */
1005 "\0\0\0\0" /* matrix[5] */
1006 "\0\0\0\0" /* matrix[6] */
1007 "\0\0\0\0" /* matrix[7] */
1008 "\100\0\0\0" /* matrix[8] */
1009 "\0\0\0\0" /* width */
1010 "\0\0\0\0" /* height */
1011 , 60);
e4bbeeb0 1012 m4af_update_box_size(ctx, pos);
48e2f01c 1013}
1014
1015static
e4bbeeb0 1016void m4af_write_trak_box(m4af_ctx_t *ctx, uint32_t track_idx)
48e2f01c 1017{
1018 int64_t pos = m4af_tell(ctx);
1019 m4af_write(ctx, "\0\0\0\0trak", 8);
e4bbeeb0 1020 m4af_write_tkhd_box(ctx, track_idx);
1021 m4af_write_mdia_box(ctx, track_idx);
1022 m4af_update_box_size(ctx, pos);
48e2f01c 1023}
1024
1025static
e4bbeeb0 1026int64_t m4af_movie_duration(m4af_ctx_t *ctx)
48e2f01c 1027{
1028 int64_t movie_duration = 0;
1029 unsigned i;
1030 for (i = 0; i < ctx->num_tracks; ++i) {
1031 double x = ctx->track[i].duration;
f67cfe22 1032 int64_t duration = x / ctx->track[i].timescale * ctx->timescale + .5;
48e2f01c 1033 if (duration > movie_duration)
1034 movie_duration = duration;
1035 }
1036 return movie_duration;
1037}
1038
1039static
e4bbeeb0 1040void m4af_write_mvhd_box(m4af_ctx_t *ctx)
48e2f01c 1041{
1042 int64_t pos = m4af_tell(ctx);
48e2f01c 1043 int64_t movie_duration = m4af_movie_duration(ctx);
f67cfe22 1044 uint8_t version = (ctx->creation_time > UINT32_MAX ||
1045 ctx->modification_time > UINT32_MAX ||
1046 movie_duration > UINT32_MAX);
48e2f01c 1047
1048 m4af_write(ctx, "\0\0\0\0mvhd", 8);
1049 m4af_write(ctx, &version, 1);
1050 m4af_write(ctx, "\0\0\0", 3); /* flags */
1051 if (version) {
1052 m4af_write64(ctx, ctx->creation_time);
1053 m4af_write64(ctx, ctx->modification_time);
1054 m4af_write32(ctx, ctx->timescale);
1055 m4af_write64(ctx, movie_duration);
1056 } else {
1057 m4af_write32(ctx, ctx->creation_time);
1058 m4af_write32(ctx, ctx->modification_time);
1059 m4af_write32(ctx, ctx->timescale);
1060 m4af_write32(ctx, movie_duration);
1061 }
1062 m4af_write(ctx,
1063 "\0\001\0\0" /* rate: 1.0 */
1064 "\001\0" /* volume: 1.0 */
1065 "\0\0" /* reserved */
1066 "\0\0\0\0" /* reserved[0] */
1067 "\0\0\0\0" /* reserved[1] */
1068 "\0\001\0\0" /* matrix[0] */
1069 "\0\0\0\0" /* matrix[1] */
1070 "\0\0\0\0" /* matrix[2] */
1071 "\0\0\0\0" /* matrix[3] */
1072 "\0\001\0\0" /* matrix[4] */
1073 "\0\0\0\0" /* matrix[5] */
1074 "\0\0\0\0" /* matrix[6] */
1075 "\0\0\0\0" /* matrix[7] */
1076 "\100\0\0\0" /* matrix[8] */
1077 "\0\0\0\0" /* pre_defined[0] */
1078 "\0\0\0\0" /* pre_defined[1] */
1079 "\0\0\0\0" /* pre_defined[2] */
1080 "\0\0\0\0" /* pre_defined[3] */
1081 "\0\0\0\0" /* pre_defined[4] */
1082 "\0\0\0\0" /* pre_defined[5] */
1083 , 76);
1084 m4af_write32(ctx, ctx->num_tracks + 1);
e4bbeeb0 1085 m4af_update_box_size(ctx, pos);
48e2f01c 1086}
1087
1088static
e4bbeeb0 1089void m4af_write_mean_box(m4af_ctx_t *ctx)
48e2f01c 1090{
1091 m4af_write(ctx,
1092 "\0\0\0\034" /* size */
1093 "mean"
1094 "\0" /* version */
1095 "\0\0\0" /* flags */
1096 "com.apple.iTunes" /* meaning-string */
1097 , 28);
1098}
1099
1100static
e4bbeeb0 1101void m4af_write_name_box(m4af_ctx_t *ctx, const char *name)
48e2f01c 1102{
1103 int64_t pos = m4af_tell(ctx);
1104 m4af_write(ctx,
1105 "\0\0\0\0" /* size */
1106 "name" /* type */
1107 "\0" /* version */
1108 "\0\0\0" /* flags */
1109 , 12);
1110 m4af_write(ctx, name, strlen(name));
e4bbeeb0 1111 m4af_update_box_size(ctx, pos);
48e2f01c 1112}
1113
1114static
e4bbeeb0 1115void m4af_write_data_box(m4af_ctx_t *ctx, uint32_t type_code,
1116 const char *data, uint32_t data_size)
48e2f01c 1117{
1118 int64_t pos = m4af_tell(ctx);
1119 uint8_t code = type_code;
1120 m4af_write(ctx,
1121 "\0\0\0\0" /* size */
1122 "data" /* type */
1123 "\0\0" /* reserved */
1124 "\0" /* type_set_indifier */
1125 ,11);
1126 m4af_write(ctx, &code, 1);
1127 m4af_write(ctx, "\0\0\0\0", 4); /* locale */
1128 m4af_write(ctx, data, data_size);
e4bbeeb0 1129 m4af_update_box_size(ctx, pos);
48e2f01c 1130}
1131
1132static
e4bbeeb0 1133void m4af_write_metadata(m4af_ctx_t *ctx, m4af_itmf_entry_t *entry)
48e2f01c 1134{
1135 int64_t pos = m4af_tell(ctx);
1136 m4af_write(ctx, "\0\0\0\0", 4);
e4bbeeb0 1137 m4af_write32(ctx, entry->fcc);
1138 if (entry->fcc != M4AF_FOURCC('-','-','-','-'))
1139 m4af_write_data_box(ctx, entry->type_code,
1140 entry->data, entry->data_size);
48e2f01c 1141 else {
e4bbeeb0 1142 m4af_write_mean_box(ctx);
1143 m4af_write_name_box(ctx, entry->name);
1144 m4af_write_data_box(ctx, 1, entry->data, entry->data_size);
48e2f01c 1145 }
e4bbeeb0 1146 m4af_update_box_size(ctx, pos);
48e2f01c 1147}
1148
1149static
e4bbeeb0 1150void m4af_write_ilst_box(m4af_ctx_t *ctx)
48e2f01c 1151{
1152 uint32_t i;
1153 int64_t pos = m4af_tell(ctx);
1154 m4af_write(ctx, "\0\0\0\0ilst", 8);
1155 for (i = 0; i < ctx->num_tags; ++i)
1156 m4af_write_metadata(ctx, &ctx->itmf_table[i]);
e4bbeeb0 1157 m4af_update_box_size(ctx, pos);
48e2f01c 1158}
1159
1160static
e4bbeeb0 1161void m4af_write_meta_box(m4af_ctx_t *ctx)
48e2f01c 1162{
1163 int64_t pos = m4af_tell(ctx);
1164 m4af_write(ctx,
1165 "\0\0\0\0" /* size */
1166 "meta" /* type */
1167 "\0" /* version */
1168 "\0\0\0" /* flags */
1169 , 12);
e4bbeeb0 1170 m4af_write_hdlr_box(ctx, 0, "mdir");
1171 m4af_write_ilst_box(ctx);
1172 m4af_update_box_size(ctx, pos);
48e2f01c 1173}
1174
1175static
e4bbeeb0 1176void m4af_write_udta_box(m4af_ctx_t *ctx)
48e2f01c 1177{
1178 int64_t pos = m4af_tell(ctx);
1179 m4af_write(ctx, "\0\0\0\0udta", 8);
e4bbeeb0 1180 m4af_write_meta_box(ctx);
1181 m4af_update_box_size(ctx, pos);
48e2f01c 1182}
1183
1184static
e4bbeeb0 1185void m4af_write_moov_box(m4af_ctx_t *ctx)
48e2f01c 1186{
1187 unsigned i;
1188 int64_t pos = m4af_tell(ctx);
1189 m4af_write(ctx, "\0\0\0\0moov", 8);
e4bbeeb0 1190 m4af_write_mvhd_box(ctx);
48e2f01c 1191 for (i = 0; i < ctx->num_tracks; ++i)
e4bbeeb0 1192 m4af_write_trak_box(ctx, i);
48e2f01c 1193 if (ctx->num_tags)
e4bbeeb0 1194 m4af_write_udta_box(ctx);
1195 m4af_update_box_size(ctx, pos);
48e2f01c 1196}
1197
1198static
e4bbeeb0 1199void m4af_finalize_mdat(m4af_ctx_t *ctx)
48e2f01c 1200{
1201 if (ctx->mdat_size + 8 > UINT32_MAX) {
1202 m4af_set_pos(ctx, ctx->mdat_pos - 16);
1203 m4af_write32(ctx, 1);
1204 m4af_write(ctx, "mdat", 4);
1205 m4af_write64(ctx, ctx->mdat_size + 16);
1206 } else {
1207 m4af_set_pos(ctx, ctx->mdat_pos - 8);
1208 m4af_write32(ctx, ctx->mdat_size + 8);
1209 }
1210 m4af_set_pos(ctx, ctx->mdat_pos + ctx->mdat_size);
1211}
1212
e4bbeeb0 1213int m4af_finalize(m4af_ctx_t *ctx)
48e2f01c 1214{
1215 unsigned i;
1216 m4af_track_t *track;
1217
1218 for (i = 0; i < ctx->num_tracks; ++i) {
1219 track = ctx->track + i;
1220 if (track->duration) {
1221 int64_t track_size = 0;
7b1f2136 1222 unsigned j;
48e2f01c 1223 for (j = 0; j < track->num_chunks; ++j)
1224 track_size += track->chunk_table[j].size;
1225 track->avgBitrate =
1226 8.0 * track_size * track->timescale / track->duration + .5;
1227 }
1228 m4af_flush_chunk(ctx, i);
1229 }
1230 if (ctx->track[0].encoder_delay || ctx->track[0].padding)
1231 m4af_set_iTunSMPB(ctx);
1232 m4af_finalize_mdat(ctx);
e4bbeeb0 1233 m4af_write_moov_box(ctx);
1234 return ctx->last_error;
48e2f01c 1235}
This page took 0.152773 seconds and 4 git commands to generate.