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