2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
17 # include <inttypes.h>
18 #elif defined _MSC_VER
19 # define PRId64 "I64d"
22 #include "m4af_endian.h"
24 #define m4af_realloc(memory,size) realloc(memory, size)
25 #define m4af_free(memory) free(memory)
26 #define m4af_max(a,b) ((a)<(b)?(b):(a))
28 #define M4AF_ATOM_WILD 0xffffffff
30 typedef struct m4af_sample_entry_t
{
33 } m4af_sample_entry_t
;
35 typedef struct m4af_chunk_entry_t
{
38 uint32_t samples_per_chunk
;
42 typedef struct m4af_itmf_entry_t
{
50 typedef struct m4af_track_t
{
53 uint16_t num_channels
;
54 int64_t creation_time
;
55 int64_t modification_time
;
57 uint32_t frame_duration
;
58 uint32_t encoder_delay
;
60 uint8_t *decSpecificInfo
;
61 uint32_t decSpecificInfoSize
;
62 uint32_t bufferSizeDB
;
67 m4af_sample_entry_t
*sample_table
;
69 uint32_t sample_table_capacity
;
71 m4af_chunk_entry_t
*chunk_table
;
73 uint32_t chunk_table_capacity
;
75 uint8_t *chunk_buffer
;
77 uint32_t chunk_capacity
;
79 /* temporary, to help parsing */
89 int64_t creation_time
;
90 int64_t modification_time
;
96 m4af_itmf_entry_t
*itmf_table
;
98 uint32_t itmf_table_capacity
;
100 m4af_io_callbacks_t io
;
104 m4af_track_t track
[2];
106 m4af_itmf_entry_t current_tag
;
109 typedef struct m4af_box_parser_t
{
111 int (*handler
)(m4af_ctx_t
*ctx
, uint32_t name
, uint64_t size
);
115 int m4af_write_null_cb(void *cookie
, const void *data
, uint32_t size
)
117 int64_t *pos
= cookie
;
122 int m4af_seek_null_cb(void *cookie
, int64_t off
, int whence
)
124 int64_t *pos
= cookie
;
125 *pos
= off
; /* XXX: we use only SEEK_SET */
129 int64_t m4af_tell_null_cb(void *cookie
)
131 return *((int64_t*)cookie
);
134 static m4af_io_callbacks_t m4af_null_io_callbacks
= {
135 0, m4af_write_null_cb
, m4af_seek_null_cb
, m4af_tell_null_cb
139 int64_t m4af_timestamp(void)
141 return (int64_t)(time(0)) + (((1970 - 1904) * 365) + 17) * 24 * 60 * 60;
146 * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
149 uint32_t m4af_roundup(uint32_t n
)
162 int64_t m4af_tell(m4af_ctx_t
*ctx
)
165 if ((pos
= ctx
->io
.tell(ctx
->io_cookie
)) < 0)
166 ctx
->last_error
= M4AF_IO_ERROR
;
171 int m4af_set_pos(m4af_ctx_t
*ctx
, int64_t pos
)
174 if ((rc
= ctx
->io
.seek(ctx
->io_cookie
, pos
, SEEK_SET
)) < 0)
175 ctx
->last_error
= M4AF_IO_ERROR
;
180 int m4af_write(m4af_ctx_t
*ctx
, const void *data
, uint32_t size
)
183 if ((rc
= ctx
->io
.write(ctx
->io_cookie
, data
, size
)) < 0)
184 ctx
->last_error
= M4AF_IO_ERROR
;
189 int m4af_write16(m4af_ctx_t
*ctx
, uint32_t data
)
191 data
= m4af_htob16(data
);
192 return m4af_write(ctx
, &data
, 2);
196 int m4af_write32(m4af_ctx_t
*ctx
, uint32_t data
)
198 data
= m4af_htob32(data
);
199 return m4af_write(ctx
, &data
, 4);
203 int m4af_write64(m4af_ctx_t
*ctx
, uint64_t data
)
205 data
= m4af_htob64(data
);
206 return m4af_write(ctx
, &data
, 8);
210 int m4af_write24(m4af_ctx_t
*ctx
, uint32_t data
)
212 data
= m4af_htob32(data
<< 8);
213 return m4af_write(ctx
, &data
, 3);
217 void m4af_write32_at(m4af_ctx_t
*ctx
, int64_t pos
, uint32_t value
)
219 int64_t current_pos
= m4af_tell(ctx
);
220 m4af_set_pos(ctx
, pos
);
221 m4af_write32(ctx
, value
);
222 m4af_set_pos(ctx
, current_pos
);
225 m4af_ctx_t
*m4af_create(uint32_t codec
, uint32_t timescale
,
226 m4af_io_callbacks_t
*io
, void *io_cookie
)
231 if (codec
!= M4AF_FOURCC('m','p','4','a') &&
232 codec
!= M4AF_FOURCC('a','l','a','c'))
234 if ((ctx
= m4af_realloc(0, sizeof(m4af_ctx_t
))) == 0)
236 memset(ctx
, 0, sizeof(m4af_ctx_t
));
237 memcpy(&ctx
->io
, io
, sizeof(m4af_io_callbacks_t
));
238 ctx
->io_cookie
= io_cookie
;
239 ctx
->timescale
= timescale
;
240 timestamp
= m4af_timestamp();
241 ctx
->creation_time
= timestamp
;
242 ctx
->modification_time
= timestamp
;
244 ctx
->track
[0].codec
= codec
;
245 ctx
->track
[0].timescale
= timescale
;
246 ctx
->track
[0].creation_time
= timestamp
;
247 ctx
->track
[0].modification_time
= timestamp
;
248 ctx
->track
[0].num_channels
= 2;
253 void m4af_free_itmf_table(m4af_ctx_t
*ctx
)
256 m4af_itmf_entry_t
*entry
= ctx
->itmf_table
;
257 for (i
= 0; i
< ctx
->num_tags
; ++i
, ++entry
) {
258 if (entry
->fcc
== M4AF_FOURCC('-','-','-','-'))
259 m4af_free(entry
->name
);
260 m4af_free(entry
->data
);
262 m4af_free(ctx
->itmf_table
);
266 void m4af_clear_track(m4af_ctx_t
*ctx
, int track_idx
)
268 m4af_track_t
*track
= ctx
->track
+ track_idx
;
269 if (track
->decSpecificInfo
)
270 m4af_free(track
->decSpecificInfo
);
271 if (track
->sample_table
)
272 m4af_free(track
->sample_table
);
273 if (track
->chunk_table
)
274 m4af_free(track
->chunk_table
);
275 if (track
->chunk_buffer
)
276 m4af_free(track
->chunk_buffer
);
277 memset(track
, 0, sizeof(m4af_track_t
));
280 void m4af_teardown(m4af_ctx_t
**ctxp
)
283 m4af_ctx_t
*ctx
= *ctxp
;
284 for (i
= 0; i
< ctx
->num_tracks
; ++i
)
285 m4af_clear_track(ctx
, i
);
287 m4af_free_itmf_table(ctx
);
292 void m4af_set_num_channels(m4af_ctx_t
*ctx
, uint32_t track_idx
,
295 ctx
->track
[track_idx
].num_channels
= channels
;
298 void m4af_set_fixed_frame_duration(m4af_ctx_t
*ctx
, uint32_t track_idx
,
301 ctx
->track
[track_idx
].frame_duration
= length
;
304 int m4af_set_decoder_specific_info(m4af_ctx_t
*ctx
, uint32_t track_idx
,
305 uint8_t *data
, uint32_t size
)
307 m4af_track_t
*track
= &ctx
->track
[track_idx
];
308 if (size
> track
->decSpecificInfoSize
) {
309 uint8_t *memory
= m4af_realloc(track
->decSpecificInfo
, size
);
311 ctx
->last_error
= M4AF_NO_MEMORY
;
314 track
->decSpecificInfo
= memory
;
317 memcpy(track
->decSpecificInfo
, data
, size
);
318 track
->decSpecificInfoSize
= size
;
320 return ctx
->last_error
;
323 void m4af_set_vbr_mode(m4af_ctx_t
*ctx
, uint32_t track_idx
, int is_vbr
)
325 m4af_track_t
*track
= &ctx
->track
[track_idx
];
326 track
->is_vbr
= is_vbr
;
329 void m4af_set_priming(m4af_ctx_t
*ctx
, uint32_t track_idx
,
330 uint32_t encoder_delay
, uint32_t padding
)
332 m4af_track_t
*track
= &ctx
->track
[track_idx
];
333 track
->encoder_delay
= encoder_delay
;
334 track
->padding
= padding
;
337 void m4af_set_priming_mode(m4af_ctx_t
*ctx
, int mode
)
339 ctx
->priming_mode
= mode
;
343 int m4af_add_sample_entry(m4af_ctx_t
*ctx
, uint32_t track_idx
,
344 uint32_t size
, uint32_t delta
)
346 m4af_track_t
*track
= &ctx
->track
[track_idx
];
347 m4af_sample_entry_t
*entry
;
351 if (track
->num_samples
== track
->sample_table_capacity
) {
352 uint32_t new_size
= track
->sample_table_capacity
;
353 new_size
= new_size
? new_size
* 2 : 1;
354 entry
= m4af_realloc(track
->sample_table
, new_size
* sizeof(*entry
));
356 ctx
->last_error
= M4AF_NO_MEMORY
;
359 track
->sample_table
= entry
;
360 track
->sample_table_capacity
= new_size
;
362 entry
= track
->sample_table
+ track
->num_samples
;
364 entry
->delta
= delta
;
365 ++track
->num_samples
;
370 int m4af_flush_chunk(m4af_ctx_t
*ctx
, uint32_t track_idx
)
372 m4af_track_t
*track
= &ctx
->track
[track_idx
];
373 m4af_chunk_entry_t
*entry
;
374 if (!track
->num_chunks
|| !track
->chunk_size
)
376 entry
= &track
->chunk_table
[track
->num_chunks
- 1];
377 entry
->offset
= m4af_tell(ctx
);
378 m4af_write(ctx
, track
->chunk_buffer
, track
->chunk_size
);
379 ctx
->mdat_size
+= track
->chunk_size
;
380 track
->chunk_size
= 0;
381 return ctx
->last_error
? -1 : 0;
385 int m4af_add_chunk_entry(m4af_ctx_t
*ctx
, uint32_t track_idx
)
387 m4af_track_t
*track
= &ctx
->track
[track_idx
];
388 m4af_chunk_entry_t
*entry
;
389 if (track
->num_chunks
== track
->chunk_table_capacity
) {
390 uint32_t new_size
= track
->chunk_table_capacity
;
391 new_size
= new_size
? new_size
* 2 : 1;
392 entry
= m4af_realloc(track
->chunk_table
, new_size
* sizeof(*entry
));
394 ctx
->last_error
= M4AF_NO_MEMORY
;
397 track
->chunk_table
= entry
;
398 track
->chunk_table_capacity
= new_size
;
400 memset(&track
->chunk_table
[track
->num_chunks
++], 0,
401 sizeof(m4af_chunk_entry_t
));
406 int m4af_update_chunk_table(m4af_ctx_t
*ctx
, uint32_t track_idx
,
407 uint32_t size
, uint32_t delta
)
409 m4af_track_t
*track
= &ctx
->track
[track_idx
];
410 m4af_chunk_entry_t
*entry
;
411 int add_new_chunk
= 0;
415 if (track
->num_chunks
== 0)
418 entry
= &track
->chunk_table
[track
->num_chunks
- 1];
419 if (entry
->duration
+ delta
> track
->timescale
/ 2)
423 m4af_flush_chunk(ctx
, track_idx
);
424 if (m4af_add_chunk_entry(ctx
, track_idx
) < 0)
427 entry
= &track
->chunk_table
[track
->num_chunks
- 1];
429 ++entry
->samples_per_chunk
;
430 entry
->duration
+= delta
;
435 void m4af_update_max_bitrate(m4af_ctx_t
*ctx
, uint32_t track_idx
)
437 m4af_track_t
*track
= &ctx
->track
[track_idx
];
438 uint32_t duration
= 0, size
= 0, bitrate
;
439 m4af_sample_entry_t
*ent
= track
->sample_table
+ track
->num_samples
- 1;
441 for (; ent
>= track
->sample_table
&& duration
< track
->timescale
; --ent
) {
442 duration
+= ent
->delta
;
445 bitrate
= (uint32_t)(size
* 8.0 * track
->timescale
/ duration
+ .5);
446 if (bitrate
> track
->maxBitrate
)
447 track
->maxBitrate
= bitrate
;
451 int m4af_append_sample_to_chunk(m4af_ctx_t
*ctx
, uint32_t track_idx
,
452 const void *data
, uint32_t size
)
454 m4af_track_t
*track
= &ctx
->track
[track_idx
];
455 uint32_t newsize
= track
->chunk_size
+ size
;
459 if (track
->chunk_capacity
< newsize
) {
460 uint32_t capacity
= m4af_roundup(newsize
);
461 uint8_t *memory
= realloc(track
->chunk_buffer
, capacity
);
463 ctx
->last_error
= M4AF_NO_MEMORY
;
466 track
->chunk_buffer
= memory
;
467 track
->chunk_capacity
= capacity
;
469 memcpy(track
->chunk_buffer
+ track
->chunk_size
, data
, size
);
470 track
->chunk_size
= newsize
;
474 int m4af_write_sample(m4af_ctx_t
*ctx
, uint32_t track_idx
, const void *data
,
475 uint32_t size
, uint32_t duration
)
477 m4af_track_t
*track
= &ctx
->track
[track_idx
];
478 if (track
->frame_duration
)
479 duration
= track
->frame_duration
;
480 if (size
> track
->bufferSizeDB
)
481 track
->bufferSizeDB
= size
;
482 track
->duration
+= duration
;
483 m4af_add_sample_entry(ctx
, track_idx
, size
, duration
);
484 m4af_update_chunk_table(ctx
, track_idx
, size
, duration
);
485 m4af_update_max_bitrate(ctx
, track_idx
);
486 m4af_append_sample_to_chunk(ctx
, track_idx
, data
, size
);
487 return ctx
->last_error
;
491 m4af_itmf_entry_t
*m4af_find_itmf_slot(m4af_ctx_t
*ctx
, uint32_t fcc
,
494 m4af_itmf_entry_t
*entry
= ctx
->itmf_table
;
497 fcc
= M4AF_FOURCC('-','-','-','-');
499 if (fcc
!= M4AF_TAG_ARTWORK
)
500 for (; entry
!= ctx
->itmf_table
+ ctx
->num_tags
; ++entry
)
501 if (fcc
== entry
->fcc
&& (!name
|| !strcmp(name
, entry
->name
)))
504 if (ctx
->num_tags
== ctx
->itmf_table_capacity
) {
505 uint32_t new_size
= ctx
->itmf_table_capacity
;
506 new_size
= new_size
? new_size
* 2 : 1;
507 entry
= m4af_realloc(ctx
->itmf_table
, new_size
* sizeof(*entry
));
509 ctx
->last_error
= M4AF_NO_MEMORY
;
512 ctx
->itmf_table
= entry
;
513 ctx
->itmf_table_capacity
= new_size
;
515 entry
= &ctx
->itmf_table
[ctx
->num_tags
++];
516 memset(entry
, 0, sizeof(m4af_itmf_entry_t
));
519 char *name_copy
= m4af_realloc(0, strlen(name
) + 1);
521 ctx
->last_error
= M4AF_NO_MEMORY
;
525 strcpy(name_copy
, name
);
526 entry
->name
= name_copy
;
531 int m4af_add_itmf_long_tag(m4af_ctx_t
*ctx
, const char *name
,
534 m4af_itmf_entry_t
*entry
;
536 size_t name_len
= strlen(name
);
537 size_t data_len
= strlen(data
);
538 if (!name_len
|| !data_len
)
541 if ((entry
= m4af_find_itmf_slot(ctx
, 0, name
)) == 0)
543 entry
->type_code
= M4AF_UTF8
;
544 if ((data_copy
= m4af_realloc(entry
->data
, data_len
)) == 0) {
545 ctx
->last_error
= M4AF_NO_MEMORY
;
548 memcpy(data_copy
, data
, data_len
);
549 entry
->data
= data_copy
;
550 entry
->data_size
= data_len
;
553 return ctx
->last_error
;
556 int m4af_add_itmf_short_tag(m4af_ctx_t
*ctx
, uint32_t fcc
,
557 uint32_t type_code
, const void *data
,
560 m4af_itmf_entry_t
*entry
;
565 if ((entry
= m4af_find_itmf_slot(ctx
, fcc
, 0)) == 0)
567 entry
->type_code
= type_code
;
568 if ((data_copy
= m4af_realloc(entry
->data
, data_size
)) == 0) {
569 ctx
->last_error
= M4AF_NO_MEMORY
;
572 memcpy(data_copy
, data
, data_size
);
573 entry
->data
= data_copy
;
574 entry
->data_size
= data_size
;
577 return ctx
->last_error
;
580 int m4af_add_itmf_string_tag(m4af_ctx_t
*ctx
, uint32_t fcc
, const char *data
)
582 return m4af_add_itmf_short_tag(ctx
, fcc
, M4AF_UTF8
, data
, strlen(data
));
585 int m4af_add_itmf_int8_tag(m4af_ctx_t
*ctx
, uint32_t fcc
, int value
)
587 uint8_t data
= value
;
588 return m4af_add_itmf_short_tag(ctx
, fcc
, M4AF_INTEGER
, &data
, 1);
591 int m4af_add_itmf_int16_tag(m4af_ctx_t
*ctx
, uint32_t fcc
, int value
)
593 uint16_t data
= m4af_htob16(value
);
594 return m4af_add_itmf_short_tag(ctx
, fcc
, M4AF_INTEGER
, &data
, 2);
597 int m4af_add_itmf_int32_tag(m4af_ctx_t
*ctx
, uint32_t fcc
, uint32_t value
)
599 uint32_t data
= m4af_htob32(value
);
600 return m4af_add_itmf_short_tag(ctx
, fcc
, M4AF_INTEGER
, &data
, 4);
603 int m4af_add_itmf_int64_tag(m4af_ctx_t
*ctx
, uint32_t fcc
, uint64_t value
)
605 uint64_t data
= m4af_htob64(value
);
606 return m4af_add_itmf_short_tag(ctx
, fcc
, M4AF_INTEGER
, &data
, 8);
609 int m4af_add_itmf_track_tag(m4af_ctx_t
*ctx
, int track
, int total
)
611 uint16_t data
[4] = { 0 };
612 data
[1] = m4af_htob16(track
);
613 data
[2] = m4af_htob16(total
);
614 return m4af_add_itmf_short_tag(ctx
, M4AF_FOURCC('t','r','k','n'),
615 M4AF_IMPLICIT
, &data
, 8);
618 int m4af_add_itmf_disk_tag(m4af_ctx_t
*ctx
, int disk
, int total
)
620 uint16_t data
[3] = { 0 };
621 data
[1] = m4af_htob16(disk
);
622 data
[2] = m4af_htob16(total
);
623 return m4af_add_itmf_short_tag(ctx
, M4AF_FOURCC('d','i','s','k'),
624 M4AF_IMPLICIT
, &data
, 6);
627 int m4af_add_itmf_genre_tag(m4af_ctx_t
*ctx
, int genre
)
629 uint16_t data
= m4af_htob16(genre
);
630 return m4af_add_itmf_short_tag(ctx
, M4AF_FOURCC('g','n','r','e'),
631 M4AF_IMPLICIT
, &data
, 2);
635 int m4af_set_iTunSMPB(m4af_ctx_t
*ctx
)
637 const char *fmt
= " 00000000 %08X %08X %08X%08X 00000000 00000000 "
638 "00000000 00000000 00000000 00000000 00000000 00000000";
639 m4af_track_t
*track
= &ctx
->track
[0];
641 uint64_t length
= track
->duration
- track
->encoder_delay
- track
->padding
;
642 sprintf(buf
, fmt
, track
->encoder_delay
, track
->padding
,
643 (uint32_t)(length
>> 32), (uint32_t)length
);
644 return m4af_add_itmf_long_tag(ctx
, "iTunSMPB", buf
);
648 uint32_t m4af_update_box_size(m4af_ctx_t
*ctx
, int64_t pos
)
650 int64_t current_pos
= m4af_tell(ctx
);
651 m4af_set_pos(ctx
, pos
);
652 m4af_write32(ctx
, current_pos
- pos
);
653 m4af_set_pos(ctx
, current_pos
);
654 return current_pos
- pos
;
658 void m4af_write_descriptor(m4af_ctx_t
*ctx
, uint32_t tag
, uint32_t size
)
662 buf
[1] = ((size
>> 21) | 0x80);
663 buf
[2] = ((size
>> 14) | 0x80);
664 buf
[3] = ((size
>> 7) | 0x80);
665 buf
[4] = (size
& 0x7f);
666 m4af_write(ctx
, buf
, 5);
670 void m4af_write_ftyp_box(m4af_ctx_t
*ctx
)
672 m4af_write(ctx
, "\0\0\0\040""ftypM4A \0\0\0\0M4A mp42isom\0\0\0\0", 32);
676 void m4af_write_free_box(m4af_ctx_t
*ctx
, uint32_t size
)
678 int64_t pos
= m4af_tell(ctx
);
679 m4af_write32(ctx
, size
+ 8);
680 m4af_write(ctx
, "free", 4);
682 m4af_set_pos(ctx
, pos
+ size
+ 8);
685 int m4af_begin_write(m4af_ctx_t
*ctx
)
687 m4af_write_ftyp_box(ctx
);
688 m4af_write_free_box(ctx
, 0);
689 m4af_write(ctx
, "\0\0\0\0mdat", 8);
690 ctx
->mdat_pos
= m4af_tell(ctx
);
691 return ctx
->last_error
;
695 void m4af_write_stco_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
697 m4af_track_t
*track
= &ctx
->track
[track_idx
];
699 m4af_chunk_entry_t
*index
= track
->chunk_table
;
700 int is_co64
= index
[track
->num_chunks
- 1].offset
> 0xffffffff;
701 int64_t pos
= m4af_tell(ctx
);
703 m4af_write32(ctx
, 0); /* size */
704 m4af_write(ctx
, is_co64
? "co64" : "stco", 4);
705 m4af_write32(ctx
, 0); /* version and flags */
706 m4af_write32(ctx
, track
->num_chunks
);
707 for (i
= 0; i
< track
->num_chunks
; ++i
, ++index
) {
709 m4af_write64(ctx
, index
->offset
);
711 m4af_write32(ctx
, index
->offset
);
713 m4af_update_box_size(ctx
, pos
);
717 void m4af_write_stsz_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
719 m4af_track_t
*track
= &ctx
->track
[track_idx
];
720 m4af_sample_entry_t
*index
= track
->sample_table
;
722 int64_t pos
= m4af_tell(ctx
);
724 "\0\0\0\0" /* size */
728 "\0\0\0\0" /* sample_size: 0(variable) */
730 m4af_write32(ctx
, track
->num_samples
);
731 for (i
= 0; i
< track
->num_samples
; ++i
, ++index
)
732 m4af_write32(ctx
, index
->size
);
733 m4af_update_box_size(ctx
, pos
);
737 void m4af_write_stsc_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
739 m4af_track_t
*track
= &ctx
->track
[track_idx
];
740 m4af_chunk_entry_t
*index
= track
->chunk_table
;
741 uint32_t i
, prev_samples_per_chunk
= 0, entry_count
= 0;
742 int64_t pos
= m4af_tell(ctx
);
744 "\0\0\0\0" /* size */
748 "\0\0\0\0" /* entry_count */
751 for (i
= 0; i
< track
->num_chunks
; ++i
, ++index
) {
752 if (index
->samples_per_chunk
!= prev_samples_per_chunk
) {
754 m4af_write32(ctx
, i
+ 1);
755 m4af_write32(ctx
, index
->samples_per_chunk
);
756 m4af_write32(ctx
, 1); /* sample_description_index */
757 prev_samples_per_chunk
= index
->samples_per_chunk
;
760 m4af_write32_at(ctx
, pos
+ 12, entry_count
);
761 m4af_update_box_size(ctx
, pos
);
765 void m4af_write_stts_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
767 m4af_track_t
*track
= &ctx
->track
[track_idx
];
768 m4af_sample_entry_t
*index
= track
->sample_table
;
769 uint32_t i
, prev_delta
= 0, entry_count
= 0, sample_count
= 0;
770 int64_t pos
= m4af_tell(ctx
);
772 "\0\0\0\0" /* size */
776 "\0\0\0\0" /* entry_count */
779 for (i
= 0; i
< track
->num_samples
; ++i
, ++index
) {
780 if (index
->delta
== prev_delta
)
785 m4af_write32(ctx
, sample_count
);
786 m4af_write32(ctx
, prev_delta
);
788 prev_delta
= index
->delta
;
793 m4af_write32(ctx
, sample_count
);
794 m4af_write32(ctx
, prev_delta
);
796 m4af_write32_at(ctx
, pos
+ 12, entry_count
);
797 m4af_update_box_size(ctx
, pos
);
801 void m4af_write_esds_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
803 m4af_track_t
*track
= &ctx
->track
[track_idx
];
804 int64_t pos
= m4af_tell(ctx
);
805 m4af_write(ctx
, "\0\0\0\0esds", 8);
806 m4af_write32(ctx
, 0); /* version + flags */
809 m4af_write_descriptor(ctx
, 3, 32 + track
->decSpecificInfoSize
);
810 m4af_write(ctx
, "\0\0\0", 3);
811 /* DecoderConfigDescriptor */
812 m4af_write_descriptor(ctx
, 4, 18 + track
->decSpecificInfoSize
);
814 "\x40" /* objectTypeIndication: 0x40(Audio ISO/IEC 14496-3)*/
815 "\x15" /* streamType(6): 0x05(AudioStream)
820 m4af_write24(ctx
, track
->bufferSizeDB
);
821 m4af_write32(ctx
, track
->maxBitrate
);
822 m4af_write32(ctx
, track
->is_vbr
? 0: track
->avgBitrate
);
823 /* DecoderSpecificInfo */
824 m4af_write_descriptor(ctx
, 5, track
->decSpecificInfoSize
);
825 m4af_write(ctx
, track
->decSpecificInfo
, track
->decSpecificInfoSize
);
826 /* SLConfigDescriptor */
827 m4af_write_descriptor(ctx
, 6, 1);
828 m4af_write(ctx
, "\002", 1); /* predefined */
830 m4af_update_box_size(ctx
, pos
);
834 void m4af_write_alac_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
836 m4af_track_t
*track
= &ctx
->track
[track_idx
];
837 int64_t pos
= m4af_tell(ctx
);
839 "\0\0\0\0" /* size */
844 m4af_write(ctx
, track
->decSpecificInfo
, track
->decSpecificInfoSize
);
845 m4af_update_box_size(ctx
, pos
);
849 void m4af_write_mp4a_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
851 m4af_track_t
*track
= &ctx
->track
[track_idx
];
852 int64_t pos
= m4af_tell(ctx
);
853 m4af_write32(ctx
, 0); /* size */
854 m4af_write32(ctx
, track
->codec
); /* mp4a or alac */
856 "\0\0\0\0\0\0" /* reserved */
857 "\0\001" /* data_reference_index: 1 */
858 "\0\0\0\0" /* reserved[0] */
859 "\0\0\0\0" /* reserved[1] */
861 m4af_write16(ctx
, track
->num_channels
);
863 "\0\020" /* samplesize: 16 */
864 "\0\0" /* pre_defined */
865 "\0\0" /* reserved */
867 if (track
->codec
== M4AF_FOURCC('m','p','4','a')) {
868 m4af_write32(ctx
, track
->timescale
<< 16);
869 m4af_write_esds_box(ctx
, track_idx
);
871 m4af_write32(ctx
, 44100 << 16);
872 m4af_write_alac_box(ctx
, track_idx
);
874 m4af_update_box_size(ctx
, pos
);
878 void m4af_write_stsd_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
880 int64_t pos
= m4af_tell(ctx
);
881 m4af_write(ctx
, "\0\0\0\0stsd", 8);
885 "\0\0\0\001" /* entry_count: 1 */
887 m4af_write_mp4a_box(ctx
, track_idx
);
888 m4af_update_box_size(ctx
, pos
);
892 void m4af_write_sbgp_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
894 m4af_track_t
*track
= &ctx
->track
[track_idx
];
896 "\0\0\0\034" /* size: 28 */
900 "roll" /* grouping_type */
901 "\0\0\0\001" /* entry_count: 1 */
903 m4af_write32(ctx
, track
->num_samples
);
904 m4af_write32(ctx
, 1); /* group_description_index */
908 void m4af_write_sgpd_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
911 "\0\0\0\026" /* size: 22 */
915 "roll" /* grouping_type */
916 "\0\0\0\001" /* entry_count: 1 */
917 "\377\377" /* payload_data: -1 */
922 void m4af_write_stbl_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
924 m4af_track_t
*track
= &ctx
->track
[track_idx
];
925 int64_t pos
= m4af_tell(ctx
);
926 m4af_write(ctx
, "\0\0\0\0stbl", 8);
927 m4af_write_stsd_box(ctx
, track_idx
);
928 if ((ctx
->priming_mode
& M4AF_PRIMING_MODE_EDTS
) &&
929 (track
->encoder_delay
|| track
->padding
)) {
930 m4af_write_sbgp_box(ctx
, track_idx
);
931 m4af_write_sgpd_box(ctx
, track_idx
);
933 m4af_write_stts_box(ctx
, track_idx
);
934 m4af_write_stsc_box(ctx
, track_idx
);
935 m4af_write_stsz_box(ctx
, track_idx
);
936 m4af_write_stco_box(ctx
, track_idx
);
937 m4af_update_box_size(ctx
, pos
);
941 void m4af_write_url_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
944 "\0\0\0\014" /* size */
947 "\0\0\001" /* flags: 1(in the same file) */
952 void m4af_write_dref_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
954 int64_t pos
= m4af_tell(ctx
);
955 m4af_write(ctx
, "\0\0\0\0dref", 8);
959 "\0\0\0\001" /* entry_count: 1 */
961 m4af_write_url_box(ctx
, track_idx
);
962 m4af_update_box_size(ctx
, pos
);
966 void m4af_write_dinf_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
968 int64_t pos
= m4af_tell(ctx
);
969 m4af_write(ctx
, "\0\0\0\0dinf", 8);
970 m4af_write_dref_box(ctx
, track_idx
);
971 m4af_update_box_size(ctx
, pos
);
975 void m4af_write_smhd_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
978 "\0\0\0\020" /* size */
983 "\0\0" /* reserved */
988 void m4af_write_minf_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
990 m4af_track_t
*track
= &ctx
->track
[track_idx
];
991 int64_t pos
= m4af_tell(ctx
);
992 m4af_write(ctx
, "\0\0\0\0minf", 8);
993 /* TODO: add TEXT support */
994 if (track
->codec
!= M4AF_CODEC_TEXT
)
995 m4af_write_smhd_box(ctx
, track_idx
);
996 m4af_write_dinf_box(ctx
, track_idx
);
997 m4af_write_stbl_box(ctx
, track_idx
);
998 m4af_update_box_size(ctx
, pos
);
1002 void m4af_write_mdhd_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1004 m4af_track_t
*track
= &ctx
->track
[track_idx
];
1005 int64_t pos
= m4af_tell(ctx
);
1006 uint8_t version
= (track
->creation_time
> UINT32_MAX
||
1007 track
->modification_time
> UINT32_MAX
||
1008 track
->duration
> UINT32_MAX
);
1010 m4af_write(ctx
, "\0\0\0\0mdhd", 8);
1011 m4af_write(ctx
, &version
, 1);
1012 m4af_write(ctx
, "\0\0\0", 3); /* flags */
1014 m4af_write64(ctx
, track
->creation_time
);
1015 m4af_write64(ctx
, track
->modification_time
);
1016 m4af_write32(ctx
, track
->timescale
);
1017 m4af_write64(ctx
, track
->duration
);
1019 m4af_write32(ctx
, track
->creation_time
);
1020 m4af_write32(ctx
, track
->modification_time
);
1021 m4af_write32(ctx
, track
->timescale
);
1022 m4af_write32(ctx
, track
->duration
);
1025 "\x55\xc4" /* language: und */
1026 "\0\0" /* pre_defined */
1028 m4af_update_box_size(ctx
, pos
);
1032 void m4af_write_hdlr_box(m4af_ctx_t
*ctx
, uint32_t track_idx
, const char *type
)
1034 int64_t pos
= m4af_tell(ctx
);
1035 static const char reserved_and_name
[10] = { 0 };
1038 "\0\0\0\0" /* size */
1041 "\0\0\0" /* flags */
1042 "\0\0\0\0" /* pre_defined */
1044 m4af_write(ctx
, type
, 4); /* handler_type */
1046 m4af_write(ctx
, !strcmp(type
, "mdir") ? "appl" : "\0\0\0\0", 4);
1047 /* reserved[1], reserved[2], name */
1048 m4af_write(ctx
, reserved_and_name
, 9);
1049 m4af_update_box_size(ctx
, pos
);
1053 void m4af_write_mdia_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1055 m4af_track_t
*track
= &ctx
->track
[track_idx
];
1057 (track
->codec
== M4AF_CODEC_TEXT
) ? "text" : "soun";
1058 int64_t pos
= m4af_tell(ctx
);
1059 m4af_write(ctx
, "\0\0\0\0mdia", 8);
1060 m4af_write_mdhd_box(ctx
, track_idx
);
1061 m4af_write_hdlr_box(ctx
, track_idx
, hdlr
);
1062 m4af_write_minf_box(ctx
, track_idx
);
1063 m4af_update_box_size(ctx
, pos
);
1067 void m4af_write_elst_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1069 m4af_track_t
*track
= &ctx
->track
[track_idx
];
1071 int64_t duration
= track
->duration
- track
->encoder_delay
- track
->padding
;
1072 int64_t pos
= m4af_tell(ctx
);
1073 duration
= (double)duration
/ track
->timescale
* ctx
->timescale
+ .5;
1074 version
= (duration
> UINT32_MAX
);
1076 m4af_write(ctx
, "\0\0\0\0elst", 8);
1077 m4af_write(ctx
, &version
, 1);
1078 m4af_write(ctx
, "\0\0\0", 3); /* flags */
1079 m4af_write32(ctx
, 1); /* entry_count: 1 */
1081 m4af_write64(ctx
, duration
);
1082 m4af_write64(ctx
, track
->encoder_delay
);
1084 m4af_write32(ctx
, duration
);
1085 m4af_write32(ctx
, track
->encoder_delay
);
1087 m4af_write16(ctx
, 1); /* media_rate_integer */
1088 m4af_write16(ctx
, 0); /* media_rate_fraction */
1089 m4af_update_box_size(ctx
, pos
);
1093 void m4af_write_edts_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1095 int64_t pos
= m4af_tell(ctx
);
1096 m4af_write(ctx
, "\0\0\0\0edts", 8);
1097 m4af_write_elst_box(ctx
, track_idx
);
1098 m4af_update_box_size(ctx
, pos
);
1102 void m4af_write_tkhd_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1104 m4af_track_t
*track
= &ctx
->track
[track_idx
];
1105 int64_t pos
= m4af_tell(ctx
);
1107 (double)track
->duration
/ track
->timescale
* ctx
->timescale
+ .5;
1108 uint8_t version
= (track
->creation_time
> UINT32_MAX
||
1109 track
->modification_time
> UINT32_MAX
||
1110 duration
> UINT32_MAX
);
1111 m4af_write(ctx
, "\0\0\0\0tkhd", 8);
1112 m4af_write(ctx
, &version
, 1);
1113 m4af_write(ctx
, "\0\0\007", 3); /* flags */
1115 m4af_write64(ctx
, track
->creation_time
);
1116 m4af_write64(ctx
, track
->modification_time
);
1117 m4af_write32(ctx
, track_idx
+ 1);
1118 m4af_write(ctx
, "\0\0\0\0" /* reserved */
1120 m4af_write64(ctx
, duration
);
1122 m4af_write32(ctx
, track
->creation_time
);
1123 m4af_write32(ctx
, track
->modification_time
);
1124 m4af_write32(ctx
, track_idx
+ 1);
1125 m4af_write(ctx
, "\0\0\0\0" /* reserved */
1127 m4af_write32(ctx
, duration
);
1130 "\0\0\0\0" /* reserved[0] */
1131 "\0\0\0\0" /* reserved[1] */
1133 "\0\0" /* alternate_group */
1134 "\001\0" /* volume: 1.0 */
1135 "\0\0" /* reserved */
1136 "\0\001\0\0" /* matrix[0] */
1137 "\0\0\0\0" /* matrix[1] */
1138 "\0\0\0\0" /* matrix[2] */
1139 "\0\0\0\0" /* matrix[3] */
1140 "\0\001\0\0" /* matrix[4] */
1141 "\0\0\0\0" /* matrix[5] */
1142 "\0\0\0\0" /* matrix[6] */
1143 "\0\0\0\0" /* matrix[7] */
1144 "\100\0\0\0" /* matrix[8] */
1145 "\0\0\0\0" /* width */
1146 "\0\0\0\0" /* height */
1148 m4af_update_box_size(ctx
, pos
);
1152 void m4af_write_trak_box(m4af_ctx_t
*ctx
, uint32_t track_idx
)
1154 m4af_track_t
*track
= &ctx
->track
[track_idx
];
1155 int64_t pos
= m4af_tell(ctx
);
1156 m4af_write(ctx
, "\0\0\0\0trak", 8);
1157 m4af_write_tkhd_box(ctx
, track_idx
);
1158 if ((ctx
->priming_mode
& M4AF_PRIMING_MODE_EDTS
) &&
1159 (track
->encoder_delay
|| track
->padding
))
1160 m4af_write_edts_box(ctx
, track_idx
);
1161 m4af_write_mdia_box(ctx
, track_idx
);
1162 m4af_update_box_size(ctx
, pos
);
1166 int64_t m4af_movie_duration(m4af_ctx_t
*ctx
)
1168 int64_t movie_duration
= 0;
1170 for (i
= 0; i
< ctx
->num_tracks
; ++i
) {
1171 double x
= ctx
->track
[i
].duration
;
1172 int64_t duration
= x
/ ctx
->track
[i
].timescale
* ctx
->timescale
+ .5;
1173 if (duration
> movie_duration
)
1174 movie_duration
= duration
;
1176 return movie_duration
;
1180 void m4af_write_mvhd_box(m4af_ctx_t
*ctx
)
1182 int64_t pos
= m4af_tell(ctx
);
1183 int64_t movie_duration
= m4af_movie_duration(ctx
);
1184 uint8_t version
= (ctx
->creation_time
> UINT32_MAX
||
1185 ctx
->modification_time
> UINT32_MAX
||
1186 movie_duration
> UINT32_MAX
);
1188 m4af_write(ctx
, "\0\0\0\0mvhd", 8);
1189 m4af_write(ctx
, &version
, 1);
1190 m4af_write(ctx
, "\0\0\0", 3); /* flags */
1192 m4af_write64(ctx
, ctx
->creation_time
);
1193 m4af_write64(ctx
, ctx
->modification_time
);
1194 m4af_write32(ctx
, ctx
->timescale
);
1195 m4af_write64(ctx
, movie_duration
);
1197 m4af_write32(ctx
, ctx
->creation_time
);
1198 m4af_write32(ctx
, ctx
->modification_time
);
1199 m4af_write32(ctx
, ctx
->timescale
);
1200 m4af_write32(ctx
, movie_duration
);
1203 "\0\001\0\0" /* rate: 1.0 */
1204 "\001\0" /* volume: 1.0 */
1205 "\0\0" /* reserved */
1206 "\0\0\0\0" /* reserved[0] */
1207 "\0\0\0\0" /* reserved[1] */
1208 "\0\001\0\0" /* matrix[0] */
1209 "\0\0\0\0" /* matrix[1] */
1210 "\0\0\0\0" /* matrix[2] */
1211 "\0\0\0\0" /* matrix[3] */
1212 "\0\001\0\0" /* matrix[4] */
1213 "\0\0\0\0" /* matrix[5] */
1214 "\0\0\0\0" /* matrix[6] */
1215 "\0\0\0\0" /* matrix[7] */
1216 "\100\0\0\0" /* matrix[8] */
1217 "\0\0\0\0" /* pre_defined[0] */
1218 "\0\0\0\0" /* pre_defined[1] */
1219 "\0\0\0\0" /* pre_defined[2] */
1220 "\0\0\0\0" /* pre_defined[3] */
1221 "\0\0\0\0" /* pre_defined[4] */
1222 "\0\0\0\0" /* pre_defined[5] */
1224 m4af_write32(ctx
, ctx
->num_tracks
+ 1);
1225 m4af_update_box_size(ctx
, pos
);
1229 void m4af_write_mean_box(m4af_ctx_t
*ctx
)
1232 "\0\0\0\034" /* size */
1235 "\0\0\0" /* flags */
1236 "com.apple.iTunes" /* meaning-string */
1241 void m4af_write_name_box(m4af_ctx_t
*ctx
, const char *name
)
1243 int64_t pos
= m4af_tell(ctx
);
1245 "\0\0\0\0" /* size */
1248 "\0\0\0" /* flags */
1250 m4af_write(ctx
, name
, strlen(name
));
1251 m4af_update_box_size(ctx
, pos
);
1255 void m4af_write_data_box(m4af_ctx_t
*ctx
, uint32_t type_code
,
1256 const char *data
, uint32_t data_size
)
1258 int64_t pos
= m4af_tell(ctx
);
1259 uint8_t code
= type_code
;
1261 "\0\0\0\0" /* size */
1263 "\0\0" /* reserved */
1264 "\0" /* type_set_indifier */
1266 m4af_write(ctx
, &code
, 1);
1267 m4af_write(ctx
, "\0\0\0\0", 4); /* locale */
1268 m4af_write(ctx
, data
, data_size
);
1269 m4af_update_box_size(ctx
, pos
);
1273 void m4af_write_metadata(m4af_ctx_t
*ctx
, m4af_itmf_entry_t
*entry
)
1275 int64_t pos
= m4af_tell(ctx
);
1276 m4af_write(ctx
, "\0\0\0\0", 4);
1277 m4af_write32(ctx
, entry
->fcc
);
1278 if (entry
->fcc
!= M4AF_FOURCC('-','-','-','-'))
1279 m4af_write_data_box(ctx
, entry
->type_code
,
1280 entry
->data
, entry
->data_size
);
1282 m4af_write_mean_box(ctx
);
1283 m4af_write_name_box(ctx
, entry
->name
);
1284 m4af_write_data_box(ctx
, 1, entry
->data
, entry
->data_size
);
1286 m4af_update_box_size(ctx
, pos
);
1290 void m4af_write_ilst_box(m4af_ctx_t
*ctx
)
1293 int64_t pos
= m4af_tell(ctx
);
1294 m4af_write(ctx
, "\0\0\0\0ilst", 8);
1295 for (i
= 0; i
< ctx
->num_tags
; ++i
)
1296 m4af_write_metadata(ctx
, &ctx
->itmf_table
[i
]);
1297 m4af_update_box_size(ctx
, pos
);
1301 void m4af_write_meta_box(m4af_ctx_t
*ctx
)
1303 int64_t pos
= m4af_tell(ctx
);
1305 "\0\0\0\0" /* size */
1308 "\0\0\0" /* flags */
1310 m4af_write_hdlr_box(ctx
, 0, "mdir");
1311 m4af_write_ilst_box(ctx
);
1312 m4af_update_box_size(ctx
, pos
);
1316 void m4af_write_udta_box(m4af_ctx_t
*ctx
)
1318 int64_t pos
= m4af_tell(ctx
);
1319 m4af_write(ctx
, "\0\0\0\0udta", 8);
1320 m4af_write_meta_box(ctx
);
1321 m4af_update_box_size(ctx
, pos
);
1325 uint32_t m4af_write_moov_box(m4af_ctx_t
*ctx
)
1328 int64_t pos
= m4af_tell(ctx
);
1329 m4af_write(ctx
, "\0\0\0\0moov", 8);
1330 m4af_write_mvhd_box(ctx
);
1331 for (i
= 0; i
< ctx
->num_tracks
; ++i
)
1332 m4af_write_trak_box(ctx
, i
);
1334 m4af_write_udta_box(ctx
);
1335 return m4af_update_box_size(ctx
, pos
);
1339 void m4af_finalize_mdat(m4af_ctx_t
*ctx
)
1341 if (ctx
->mdat_size
+ 8 > UINT32_MAX
) {
1342 m4af_set_pos(ctx
, ctx
->mdat_pos
- 16);
1343 m4af_write32(ctx
, 1);
1344 m4af_write(ctx
, "mdat", 4);
1345 m4af_write64(ctx
, ctx
->mdat_size
+ 16);
1347 m4af_set_pos(ctx
, ctx
->mdat_pos
- 8);
1348 m4af_write32(ctx
, ctx
->mdat_size
+ 8);
1350 m4af_set_pos(ctx
, ctx
->mdat_pos
+ ctx
->mdat_size
);
1354 uint64_t m4af_patch_moov(m4af_ctx_t
*ctx
, uint32_t moov_size
, uint32_t offset
)
1357 uint32_t moov_size2
;
1359 m4af_io_callbacks_t io_reserve
= ctx
->io
;
1360 void *io_cookie_reserve
= ctx
->io_cookie
;
1362 for (i
= 0; i
< ctx
->num_tracks
; ++i
)
1363 for (j
= 0; j
< ctx
->track
[i
].num_chunks
; ++j
)
1364 ctx
->track
[i
].chunk_table
[j
].offset
+= offset
;
1366 ctx
->io
= m4af_null_io_callbacks
;
1367 ctx
->io_cookie
= &pos
;
1368 moov_size2
= m4af_write_moov_box(ctx
);
1370 if (moov_size2
!= moov_size
) {
1371 /* stco -> co64 switching */
1372 for (i
= 0; i
< ctx
->num_tracks
; ++i
)
1373 for (j
= 0; j
< ctx
->track
[i
].num_chunks
; ++j
)
1374 ctx
->track
[i
].chunk_table
[j
].offset
+= moov_size2
- moov_size
;
1375 moov_size2
= m4af_write_moov_box(ctx
);
1377 ctx
->io
= io_reserve
;
1378 ctx
->io_cookie
= io_cookie_reserve
;
1383 void m4af_shift_mdat_pos(m4af_ctx_t
*ctx
, uint32_t offset
)
1388 buf
= malloc(1024*1024*2);
1390 end
= ctx
->mdat_pos
+ ctx
->mdat_size
;
1391 for (; (begin
= m4af_max(ctx
->mdat_pos
, end
- 1024*1024*2)) < end
;
1393 m4af_set_pos(ctx
, begin
);
1394 ctx
->io
.read(ctx
->io_cookie
, buf
, end
- begin
);
1395 m4af_set_pos(ctx
, begin
+ offset
);
1396 m4af_write(ctx
, buf
, end
- begin
);
1398 ctx
->mdat_pos
+= offset
;
1399 m4af_set_pos(ctx
, ctx
->mdat_pos
- 16);
1400 m4af_write_free_box(ctx
, 0);
1401 m4af_write(ctx
, "\0\0\0\0mdat", 8);
1402 m4af_finalize_mdat(ctx
);
1407 int m4af_finalize(m4af_ctx_t
*ctx
, int optimize
)
1410 m4af_track_t
*track
;
1413 for (i
= 0; i
< ctx
->num_tracks
; ++i
) {
1414 track
= ctx
->track
+ i
;
1415 if (track
->duration
) {
1416 int64_t track_size
= 0;
1418 for (j
= 0; j
< track
->num_chunks
; ++j
)
1419 track_size
+= track
->chunk_table
[j
].size
;
1421 8.0 * track_size
* track
->timescale
/ track
->duration
+ .5;
1423 m4af_flush_chunk(ctx
, i
);
1426 if ((ctx
->priming_mode
& M4AF_PRIMING_MODE_ITUNSMPB
) &&
1427 (track
->encoder_delay
|| track
->padding
))
1428 m4af_set_iTunSMPB(ctx
);
1429 m4af_finalize_mdat(ctx
);
1430 moov_size
= m4af_write_moov_box(ctx
);
1433 uint32_t moov_size2
= m4af_patch_moov(ctx
, moov_size
, moov_size
+ 1024);
1434 m4af_shift_mdat_pos(ctx
, moov_size2
+ 1024);
1435 m4af_set_pos(ctx
, 32);
1436 m4af_write_moov_box(ctx
);
1437 pos
= m4af_tell(ctx
);
1438 m4af_write_free_box(ctx
, ctx
->mdat_pos
- pos
- 24);
1440 return ctx
->last_error
;