From fddfeaab68aac1d9cbdb8ba466545f99e36b4484 Mon Sep 17 00:00:00 2001 From: John Regan Date: Sat, 23 Apr 2022 10:41:54 -0400 Subject: [PATCH] Add methods for manual flushing and changing write offset Use case - generating fragmented MP4s for HLS streaming requires creating an initialization segment with decoder-specific config (the moov box). Manual flush allows writing out the moov box before adding samples. Similar with write offset - after writing the moov box, one wants to write media segments that begin with a moof box and have 1 or more mdat boxes. This adds a method for overwriting the write offset, in case the library user wants to treat MP4E_mux_t as an opaque type. --- minimp4.h | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/minimp4.h b/minimp4.h index d31e783..d80dd78 100644 --- a/minimp4.h +++ b/minimp4.h @@ -433,6 +433,18 @@ int MP4E_add_track(MP4E_mux_t *mux, const MP4E_track_t *track_data); */ int MP4E_put_sample(MP4E_mux_t *mux, int track_num, const void *data, int data_bytes, int duration, int kind); +/** +* Writes the MP4 index if not already written, and any pending track data +* +* return error code MP4E_STATUS_* +*/ +int MP4E_flush(MP4E_mux_t *mux); + +/** +* Set the file position for the next write operation +*/ +void MP4E_set_write_pos(MP4E_mux_t *mux, int64_t write_pos); + /** * Finalize MP4 file, de-allocated memory, and closes MP4 multiplexer. * The close operation takes a time and disk space, since it writes MP4 file @@ -696,6 +708,7 @@ typedef struct MP4E_mux_tag int sequential_mode_flag; int enable_fragmentation; // flag, indicating streaming-friendly 'fragmentation' mode int fragments_count; // # of fragments in 'fragmentation' mode + int index_flushed; // flag, indicating if the index has been written } MP4E_mux_t; @@ -817,6 +830,7 @@ MP4E_mux_t *MP4E_open(int sequential_mode_flag, int enable_fragmentation, void * mux->sequential_mode_flag = sequential_mode_flag || enable_fragmentation; mux->enable_fragmentation = enable_fragmentation; mux->fragments_count = 0; + mux->index_flushed = 0; mux->write_callback = write_callback; mux->token = token; mux->text_comment = NULL; @@ -1108,8 +1122,10 @@ int MP4E_put_sample(MP4E_mux_t *mux, int track_num, const void *data, int data_b // NOTE: assume a constant `duration` to calculate current timestamp uint64_t timestamp = (uint64_t)mux->fragments_count * duration; #endif - if (!mux->fragments_count++) + if (!mux->index_flushed) { ERR(mp4e_flush_index(mux)); // write file headers before 1st sample + mux->index_flushed = 1; + } // write MOOF + MDAT + sample data #if MP4D_TFDT_SUPPORT ERR(mp4e_write_fragment_header(mux, track_num, data_bytes, duration, kind, timestamp)); @@ -1739,6 +1755,27 @@ static int mp4e_flush_index(MP4E_mux_t *mux) return err; } +int MP4E_flush(MP4E_mux_t *mux) { + unsigned int ntr, ntracks = mux->tracks.bytes / sizeof(track_t); + + if (!mux->index_flushed) { + ERR(mp4e_flush_index(mux)); + mux->index_flushed = 1; + } + + for (ntr = 0; ntr < ntracks; ntr++) + { + track_t *tr = ((track_t*)mux->tracks.data) + ntr; + ERR(write_pending_data(mux, tr)); + } + + return MP4E_STATUS_OK; +} + +void MP4E_set_write_pos(MP4E_mux_t *mux, int64_t write_pos) { + mux->write_pos = write_pos; +} + int MP4E_close(MP4E_mux_t *mux) { int err = MP4E_STATUS_OK;