Using av_interleaved_write_frame in FFmpeg

This article explains how to write individual media packets to an output container using the FFmpeg av_interleaved_write_frame function. You will learn how to initialize the output context, rescale presentation and decoding timestamps (PTS/DTS) to match container time bases, pass encoded packets to the interleaving queue, and finalize the stream output correctly.

1. Initialize the Output Context and Write the Header

Before writing any packets, you must allocate an output format context (AVFormatContext), create the necessary video or audio streams (AVStream), and write the container header using avformat_write_header.

AVFormatContext *out_ctx = NULL;
avformat_alloc_output_context2(&out_ctx, NULL, NULL, "output.mp4");

// Add an AVStream and configure its codec parameters here...

// Open output file if needed
if (!(out_ctx->oformat->flags & AVFMT_NOFILE)) {
    avio_open(&out_ctx->pb, "output.mp4", AVIO_FLAG_WRITE);
}

// Write the stream header
if (avformat_write_header(out_ctx, NULL) < 0) {
    // Handle error
}

2. Prepare the AVPacket and Rescale Timestamps

Each encoded packet (AVPacket) produced by your encoder uses the encoder's time base (AVCodecContext::time_base). Container formats typically require timestamps expressed in the stream's time base (AVStream::time_base).

Before writing, set the stream index and rescale the packet's pts, dts, and duration values using av_packet_rescale_ts:

// Assign the packet to the corresponding stream index
pkt->stream_index = stream->index;

// Rescale timestamps from codec timebase to stream timebase
av_packet_rescale_ts(pkt, codec_ctx->time_base, stream->time_base);

3. Write the Packet with av_interleaved_write_frame

The av_interleaved_write_frame function buffers packets internally to ensure that audio and video packets are written in ascending order of their Decoding Timestamp (DTS). This prevents playback stuttering and ensures container specification compliance.

int ret = av_interleaved_write_frame(out_ctx, pkt);
if (ret < 0) {
    // Handle write error
}

Note that av_interleaved_write_frame takes ownership of the packet data if the call succeeds, automatically unreferencing the packet buffers. If you need to reuse the AVPacket structure, allocate a fresh reference or allocate it via av_packet_alloc().

4. Flush the Interleaver and Finalize the Output

Once all frames are encoded and written, any remaining packets buffered inside the interleaver must be flushed to disk. Pass NULL to av_interleaved_write_frame to flush the internal buffer, write the container trailer with av_write_trailer, and clean up resources:

// Flush any buffered interleaved packets
av_interleaved_write_frame(out_ctx, NULL);

// Write the file trailer
av_write_trailer(out_ctx);

// Clean up
if (!(out_ctx->oformat->flags & AVFMT_NOFILE)) {
    avio_closep(&out_ctx->pb);
}
avformat_free_context(out_ctx);