remux

expect suspend fun remux(input: String, output: String, streamIndices: List<Int>? = null, startMicros: Long = 0, endMicros: Long = Long.MAX_VALUE, metadata: Map<String, String> = emptyMap(), dispatcher: CoroutineDispatcher? = null, onProgress: (packetsWritten: Long) -> Unit? = null)

Copy streamIndices (default: every stream the demuxer understands) from input into a fresh container at output. Format inferred from the output extension.

The cut is keyframe-snapped, which is the price of not re-encoding: it starts at the last keyframe at or before startMicros and stops once the first selected stream passes endMicros. The pictures that follow that keyframe in decode order but show before it lean on a picture the cut does not copy, so no decoder could show them, and they are left out.

The output's timeline starts at zero where its media starts to show: the earliest picture, and the first sound after the samples a stream hides at its start, such as an AAC encoder's priming or what an MP4 edit list cuts, which is how FFmpeg reads where a stream starts. So a whole remux plays exactly as the input does.

Each copied stream keeps its tags (language, title and the rest), its disposition flags and its display matrix, and the output gets the input's chapters that overlap what it copies, from the keyframe it starts on to endMicros, moved by as much as the media so each still starts on its own frame. What the target container cannot store is dropped by its muxer: MP4 has no stream titles, and Matroska has no display matrix. A language named by a BCP 47 tag such as pt-BR goes into MP4, MOV and MPEG-TS as the three-letter code of its language, because their field holds only such a code; Matroska keeps the whole tag as well.

A container pair that needs a bitstream filter, such as H.264 in MP4 to MPEG-TS, gets it automatically: libavformat inserts the filter when the packets are written.

The copy loop runs on dispatcher, so a call from an app's main thread does not block it. Cancelling the caller stops the loop before its next packet. Every native object is closed before this function returns or throws, and the output is finished with whatever was written up to that point.

Parameters

startMicros

trim start, relative to the start of the content (see MediaSource.startTimeMicros)

endMicros

trim end, on the same content-relative scale

metadata

container tags written into the output header (title, artist, …)

dispatcher

where the blocking work runs. Null runs it on Dispatchers.IO, the pool for blocking calls.

onProgress

invoked every ~100 packets with the running packet count, in the caller's own coroutine context and never on dispatcher. A caller that is busy when a report arrives gets only the newest one, and the last report arrives before this function returns.

Throws

when the input cannot be opened, the output cannot be written, or a packet cannot be copied. Swift and Objective-C receive it as an error.


expect suspend fun remux(input: String, inputOptions: Map<String, String>, output: String, streamIndices: List<Int>? = null, startMicros: Long = 0, endMicros: Long = Long.MAX_VALUE, metadata: Map<String, String> = emptyMap(), dispatcher: CoroutineDispatcher? = null, onProgress: (packetsWritten: Long) -> Unit? = null)

remux with pre-open options for input, applied the way MediaSource.open applies them. On Android this reads a file the user picked without copying it: pass "fd:" as input and the descriptor number as the fd option. Every other parameter is as in the path overload.

Throws

as the path overload does. Swift and Objective-C receive it as an error.


expect suspend fun remux(input: () -> MediaByteSource, output: MediaByteSink, format: String, outputOptions: Map<String, String> = emptyMap(), streamIndices: List<Int>? = null, startMicros: Long = 0, endMicros: Long = Long.MAX_VALUE, metadata: Map<String, String> = emptyMap(), dispatcher: CoroutineDispatcher? = null, onProgress: (packetsWritten: Long) -> Unit? = null)

remux from bytes the caller supplies into bytes the caller keeps, with no path at either end. Every other parameter is as in the path overload.

Parameters

input

opens a fresh source at position zero. The remux calls it once and closes the source.

output

receives the file. The remux owns it and closes it, as MediaSink.open does.

format

the output container, such as mp4 or matroska, because there is no file name to infer it from.

outputOptions

muxer options, as MediaSink.open takes them. An output that cannot seek needs a layout that never goes back, such as MP4 with movflags set to frag_keyframe+empty_moov.

Throws

as the path overload does. Swift and Objective-C receive it as an error.

actual suspend fun remux(input: String, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)
actual suspend fun remux(input: String, inputOptions: Map<String, String>, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)
actual suspend fun remux(input: () -> MediaByteSource, output: MediaByteSink, format: String, outputOptions: Map<String, String>, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)
actual suspend fun remux(input: String, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

Copy streamIndices (default: every stream the demuxer understands) from input into a fresh container at output. Format inferred from the output extension.

The cut is keyframe-snapped, which is the price of not re-encoding: it starts at the last keyframe at or before startMicros and stops once the first selected stream passes endMicros. The pictures that follow that keyframe in decode order but show before it lean on a picture the cut does not copy, so no decoder could show them, and they are left out.

The output's timeline starts at zero where its media starts to show: the earliest picture, and the first sound after the samples a stream hides at its start, such as an AAC encoder's priming or what an MP4 edit list cuts, which is how FFmpeg reads where a stream starts. So a whole remux plays exactly as the input does.

Each copied stream keeps its tags (language, title and the rest), its disposition flags and its display matrix, and the output gets the input's chapters that overlap what it copies, from the keyframe it starts on to endMicros, moved by as much as the media so each still starts on its own frame. What the target container cannot store is dropped by its muxer: MP4 has no stream titles, and Matroska has no display matrix. A language named by a BCP 47 tag such as pt-BR goes into MP4, MOV and MPEG-TS as the three-letter code of its language, because their field holds only such a code; Matroska keeps the whole tag as well.

A container pair that needs a bitstream filter, such as H.264 in MP4 to MPEG-TS, gets it automatically: libavformat inserts the filter when the packets are written.

The copy loop runs on dispatcher, so a call from an app's main thread does not block it. Cancelling the caller stops the loop before its next packet. Every native object is closed before this function returns or throws, and the output is finished with whatever was written up to that point.

Parameters

startMicros

trim start, relative to the start of the content (see MediaSource.startTimeMicros)

endMicros

trim end, on the same content-relative scale

metadata

container tags written into the output header (title, artist, …)

dispatcher

where the blocking work runs. Null runs it on Dispatchers.IO, the pool for blocking calls.

onProgress

invoked every ~100 packets with the running packet count, in the caller's own coroutine context and never on dispatcher. A caller that is busy when a report arrives gets only the newest one, and the last report arrives before this function returns.

Throws

when the input cannot be opened, the output cannot be written, or a packet cannot be copied. Swift and Objective-C receive it as an error.


actual suspend fun remux(input: String, inputOptions: Map<String, String>, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

remux with pre-open options for input, applied the way MediaSource.open applies them. On Android this reads a file the user picked without copying it: pass "fd:" as input and the descriptor number as the fd option. Every other parameter is as in the path overload.

Throws

as the path overload does. Swift and Objective-C receive it as an error.


actual suspend fun remux(input: () -> MediaByteSource, output: MediaByteSink, format: String, outputOptions: Map<String, String>, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

remux from bytes the caller supplies into bytes the caller keeps, with no path at either end. Every other parameter is as in the path overload.

Parameters

input

opens a fresh source at position zero. The remux calls it once and closes the source.

output

receives the file. The remux owns it and closes it, as MediaSink.open does.

format

the output container, such as mp4 or matroska, because there is no file name to infer it from.

outputOptions

muxer options, as MediaSink.open takes them. An output that cannot seek needs a layout that never goes back, such as MP4 with movflags set to frag_keyframe+empty_moov.

Throws

as the path overload does. Swift and Objective-C receive it as an error.

actual suspend fun remux(input: String, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

Copy streamIndices (default: every stream the demuxer understands) from input into a fresh container at output. Format inferred from the output extension.

The cut is keyframe-snapped, which is the price of not re-encoding: it starts at the last keyframe at or before startMicros and stops once the first selected stream passes endMicros. The pictures that follow that keyframe in decode order but show before it lean on a picture the cut does not copy, so no decoder could show them, and they are left out.

The output's timeline starts at zero where its media starts to show: the earliest picture, and the first sound after the samples a stream hides at its start, such as an AAC encoder's priming or what an MP4 edit list cuts, which is how FFmpeg reads where a stream starts. So a whole remux plays exactly as the input does.

Each copied stream keeps its tags (language, title and the rest), its disposition flags and its display matrix, and the output gets the input's chapters that overlap what it copies, from the keyframe it starts on to endMicros, moved by as much as the media so each still starts on its own frame. What the target container cannot store is dropped by its muxer: MP4 has no stream titles, and Matroska has no display matrix. A language named by a BCP 47 tag such as pt-BR goes into MP4, MOV and MPEG-TS as the three-letter code of its language, because their field holds only such a code; Matroska keeps the whole tag as well.

A container pair that needs a bitstream filter, such as H.264 in MP4 to MPEG-TS, gets it automatically: libavformat inserts the filter when the packets are written.

The copy loop runs on dispatcher, so a call from an app's main thread does not block it. Cancelling the caller stops the loop before its next packet. Every native object is closed before this function returns or throws, and the output is finished with whatever was written up to that point.

Parameters

startMicros

trim start, relative to the start of the content (see MediaSource.startTimeMicros)

endMicros

trim end, on the same content-relative scale

metadata

container tags written into the output header (title, artist, …)

dispatcher

where the blocking work runs. Null runs it on Dispatchers.IO, the pool for blocking calls.

onProgress

invoked every ~100 packets with the running packet count, in the caller's own coroutine context and never on dispatcher. A caller that is busy when a report arrives gets only the newest one, and the last report arrives before this function returns.

Throws

when the input cannot be opened, the output cannot be written, or a packet cannot be copied. Swift and Objective-C receive it as an error.


actual suspend fun remux(input: String, inputOptions: Map<String, String>, output: String, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

remux with pre-open options for input, applied the way MediaSource.open applies them. On Android this reads a file the user picked without copying it: pass "fd:" as input and the descriptor number as the fd option. Every other parameter is as in the path overload.

Throws

as the path overload does. Swift and Objective-C receive it as an error.


actual suspend fun remux(input: () -> MediaByteSource, output: MediaByteSink, format: String, outputOptions: Map<String, String>, streamIndices: List<Int>?, startMicros: Long, endMicros: Long, metadata: Map<String, String>, dispatcher: CoroutineDispatcher?, onProgress: (packetsWritten: Long) -> Unit?)

remux from bytes the caller supplies into bytes the caller keeps, with no path at either end. Every other parameter is as in the path overload.

Parameters

input

opens a fresh source at position zero. The remux calls it once and closes the source.

output

receives the file. The remux owns it and closes it, as MediaSink.open does.

format

the output container, such as mp4 or matroska, because there is no file name to infer it from.

outputOptions

muxer options, as MediaSink.open takes them. An output that cannot seek needs a layout that never goes back, such as MP4 with movflags set to frag_keyframe+empty_moov.

Throws

as the path overload does. Swift and Objective-C receive it as an error.