Handling AVERROR(EAGAIN) and AVERROR_EOF in FFmpeg

In the FFmpeg C API, processing audio and video relies on an asynchronous send/receive model where AVERROR(EAGAIN) and AVERROR_EOF are operational flow-control signals rather than critical errors. This guide explains the exact meaning of these return codes within the avcodec_send_* and avcodec_receive_* functions, detailing how to properly structure your encoding or decoding loops to prevent deadlocks, data loss, and segmentation faults.

The Send/Receive API Paradigm

FFmpeg decouples input and output using two primary function pairs:

  • Decoding: avcodec_send_packet() supplies compressed data, and avcodec_receive_frame() extracts uncompressed frames.
  • Encoding: avcodec_send_frame() supplies raw frames, and avcodec_receive_packet() extracts compressed packets.

Because a single input packet can generate zero, one, or multiple frames (and vice versa for encoding), the API relies on AVERROR(EAGAIN) and AVERROR_EOF to manage internal buffers.


What AVERROR(EAGAIN) Means

AVERROR(EAGAIN) indicates that the internal state cannot proceed with the requested operation until you perform the complementary action.

  1. When returned by avcodec_receive_frame() or avcodec_receive_packet():
    • Meaning: The internal buffer is empty. The codec requires more input before it can emit new output.
    • Action: Stop calling the receive function. Read the next packet or frame from your demuxer/source and provide it via the corresponding send function.
  2. When returned by avcodec_send_packet() or avcodec_send_frame():
    • Meaning: The internal buffer is full. The codec cannot accept new input until the existing output is consumed.
    • Action: Stop sending data. Repeatedly call the receive function until it returns AVERROR(EAGAIN), draining the internal buffer, then retry sending the original input.

What AVERROR_EOF Means

AVERROR_EOF indicates that the stream has ended and the codec has been completely flushed.

  1. Flushing the Codec:
    • To signal the end of a stream, send a NULL pointer to avcodec_send_packet() or avcodec_send_frame().
    • Once the flush packet/frame is sent, calling the send function again will return AVERROR_EOF.
  2. Draining Remaining Data:
    • After flushing, existing buffered frames or packets remain inside the codec.
    • Continue calling avcodec_receive_frame() or avcodec_receive_packet() in a loop. It will return valid data until the codec is entirely empty.
    • Once all buffered data is output, the receive function returns AVERROR_EOF. At this point, no further output will be produced, and the processing loop should terminate.

Canonical Decoding Loop Example

The following pattern demonstrates how to handle both return codes correctly during decoding:

int ret = 0;
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();

while (av_read_frame(fmt_ctx, pkt) >= 0) {
    if (pkt->stream_index == video_stream_idx) {
        // Send packet to decoder
        ret = avcodec_send_packet(codec_ctx, pkt);
        if (ret < 0) {
            // AVERROR(EAGAIN) here means you must drain frames first,
            // though standard usage typically drains after every send.
            fprintf(stderr, "Error sending packet: %d\n", ret);
            break;
        }

        // Receive all available frames
        while (ret >= 0) {
            ret = avcodec_receive_frame(codec_ctx, frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                // EAGAIN: Need more packets to output another frame.
                // EOF: End of stream reached (if flushed).
                break;
            } else if (ret < 0) {
                // Actual fatal error
                fprintf(stderr, "Error receiving frame: %d\n", ret);
                goto end;
            }

            // Successfully decoded a frame
            process_frame(frame);
            av_frame_unref(frame);
        }
    }
    av_packet_unref(pkt);
}

// Flush decoder: send NULL to signal EOF
ret = avcodec_send_packet(codec_ctx, NULL);

// Drain remaining cached frames
while (ret >= 0) {
    ret = avcodec_receive_frame(codec_ctx, frame);
    if (ret == AVERROR_EOF) {
        // Codec fully drained
        break;
    } else if (ret == AVERROR(EAGAIN)) {
        // Should not occur after a flush, but break if it does
        break;
    } else if (ret < 0) {
        fprintf(stderr, "Error draining frame: %d\n", ret);
        break;
    }

    process_frame(frame);
    av_frame_unref(frame);
}

end:
av_packet_free(&pkt);
av_frame_free(&frame);

Key Rules to Remember

  • Never treat AVERROR(EAGAIN) as fatal: Treat it as a prompt to switch between reading and writing.
  • Do not discard unconsumed inputs: If avcodec_send_* returns AVERROR(EAGAIN), retain the current packet or frame, drain the output with avcodec_receive_*, and resubmit the same input.
  • Always drain after sending NULL: Codecs often hold several delayed frames for B-frame reordering; skipping the final AVERROR_EOF drain loop will truncate the end of the media stream.