Handling AVERROR(EAGAIN) and AVERROR_EOF in FFmpeg
Working with the FFmpeg C API requires robust error handling,
especially when decoding video or audio streams. This article explains
how to properly handle the AVERROR(EAGAIN) and
AVERROR_EOF return codes during the packet-sending and
frame-receiving process to ensure your application decodes media streams
without crashes or data loss.
The FFmpeg Decoding Loop
FFmpeg uses a push-pull model for decoding, split into two main
functions: avcodec_send_packet() and
avcodec_receive_frame().
avcodec_send_packet()pushes compressed raw data (packets) into the decoder.avcodec_receive_frame()pulls decompressed media data (frames) out of the decoder.
Because one input packet can produce zero, one, or multiple output frames, you must handle specific non-fatal return codes to manage the flow of data.
Handling AVERROR(EAGAIN)
AVERROR(EAGAIN) is not a critical error; it is a status
indicator telling you that the state of the codec context must change
before you can proceed with the current operation.
1. In
avcodec_send_packet()
If avcodec_send_packet() returns
AVERROR(EAGAIN), it means the decoder’s internal buffer is
full. It cannot accept new packets until you drain the existing decoded
frames.
- What to do: Stop sending packets, call
avcodec_receive_frame()in a loop to retrieve all decoded frames, and then attempt to send the packet again.
2. In
avcodec_receive_frame()
If avcodec_receive_frame() returns
AVERROR(EAGAIN), it means the decoder requires more input
data to produce a new frame.
- What to do: Stop calling
avcodec_receive_frame()and feed a new packet to the decoder usingavcodec_send_packet().
Handling AVERROR_EOF
AVERROR_EOF signals the “End of File” or end of the
stream. Like AVERROR(EAGAIN), it is a control flow signal
rather than a failure.
1. In
avcodec_send_packet()
If you receive AVERROR_EOF here, it means the decoder
has been flushed (you sent a NULL packet to signal the end
of the stream) and is in draining port mode. No further packets can be
sent to this decoder context.
2. In
avcodec_receive_frame()
When avcodec_receive_frame() returns
AVERROR_EOF, the decoder has finished processing all
buffered packets and has output its final frames.
- What to do: Cleanly shut down your decoding loop or move to the next stream. The decoding process for this stream is successfully complete.
Code Implementation Example
The following C code demonstrates how to structure a standard decoding loop to handle both return codes correctly.
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
int response = 0;
while (av_read_frame(format_context, packet) >= 0) {
if (packet->stream_index == video_stream_index) {
// Send the packet to the decoder
response = avcodec_send_packet(codec_context, packet);
if (response < 0) {
// ERROR(EAGAIN) here means we must drain the decoder before sending more packets
if (response != AVERROR(EAGAIN) && response != AVERROR_EOF) {
fprintf(stderr, "Error sending packet to decoder\n");
return response;
}
}
// Receive decoded frames from the decoder
while (response >= 0) {
response = avcodec_receive_frame(codec_context, frame);
if (response == AVERROR(EAGAIN)) {
// Decoder needs more packets to produce a frame; safe to break and read next packet
break;
} else if (response == AVERROR_EOF) {
// End of file/stream reached cleanly
printf("Decoder flushed, end of stream reached.\n");
break;
} else if (response < 0) {
fprintf(stderr, "Error receiving frame from decoder\n");
return response;
}
// Successfully received a frame; process it here
process_decoded_frame(frame);
av_frame_unref(frame);
}
}
av_packet_unref(packet);
}
// Clean up resources
av_packet_free(&packet);
av_frame_free(&frame);