+static
+uint64_t m4af_patch_moov(m4af_ctx_t *ctx, uint32_t moov_size, uint32_t offset)
+{
+ int64_t pos = 0;
+ uint32_t moov_size2;
+ int i, j;
+ m4af_io_callbacks_t io_reserve = ctx->io;
+ void *io_cookie_reserve = ctx->io_cookie;
+
+ for (i = 0; i < ctx->num_tracks; ++i)
+ for (j = 0; j < ctx->track[i].num_chunks; ++j)
+ ctx->track[i].chunk_table[j].offset += offset;
+
+ ctx->io = m4af_null_io_callbacks;
+ ctx->io_cookie = &pos;
+ moov_size2 = m4af_write_moov_box(ctx);
+
+ if (moov_size2 != moov_size) {
+ /* stco -> co64 switching */
+ for (i = 0; i < ctx->num_tracks; ++i)
+ for (j = 0; j < ctx->track[i].num_chunks; ++j)
+ ctx->track[i].chunk_table[j].offset += moov_size2 - moov_size;
+ moov_size2 = m4af_write_moov_box(ctx);
+ }
+ ctx->io = io_reserve;
+ ctx->io_cookie = io_cookie_reserve;
+ return moov_size2;
+}
+
+static
+void m4af_shift_mdat_pos(m4af_ctx_t *ctx, uint32_t offset)
+{
+ int64_t begin, end;
+ char *buf;
+
+ buf = malloc(1024*1024*2);
+
+ end = ctx->mdat_pos + ctx->mdat_size;
+ for (; (begin = m4af_max(ctx->mdat_pos, end - 1024*1024*2)) < end;
+ end = begin) {
+ m4af_set_pos(ctx, begin);
+ ctx->io.read(ctx->io_cookie, buf, end - begin);
+ m4af_set_pos(ctx, begin + offset);
+ m4af_write(ctx, buf, end - begin);
+ }
+ ctx->mdat_pos += offset;
+ m4af_set_pos(ctx, ctx->mdat_pos - 16);
+ m4af_write_free_box(ctx, 0);
+ m4af_write(ctx, "\0\0\0\0mdat", 8);
+ m4af_finalize_mdat(ctx);
+
+ free(buf);
+}
+
+int m4af_finalize(m4af_ctx_t *ctx, int optimize)