Allocate AVCodecContext for Video in FFmpeg C API

This guide demonstrates how to properly allocate, configure, and initialize an AVCodecContext for decoding a video stream using the modern FFmpeg C API. The process involves identifying the video stream, finding the appropriate decoder, allocating the context using avcodec_alloc_context3, copying parameters from AVCodecParameters, and opening the codec with avcodec_open2.

Step-by-Step Implementation

In modern FFmpeg (libavcodec 57 and newer), stream configuration details are stored in an AVCodecParameters struct inside the AVStream. You must allocate a new AVCodecContext independently and copy the stream parameters into it.

1. Locate the Video Stream and Decoder

First, identify the video stream index from your opened AVFormatContext and locate the corresponding AVCodec:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

AVFormatContext *fmt_ctx = /* initialized AVFormatContext */;
const AVCodec *decoder = NULL;

// Find the best video stream and its decoder
int video_stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
if (video_stream_idx < 0) {
    // Handle error: No video stream found
    return -1;
}

AVStream *video_stream = fmt_ctx->streams[video_stream_idx];

2. Allocate the AVCodecContext

Allocate the context using avcodec_alloc_context3(). Passing the decoder pointer automatically sets default values specific to that codec:

AVCodecContext *codec_ctx = avcodec_alloc_context3(decoder);
if (!codec_ctx) {
    // Handle error: Out of memory
    return -1;
}

3. Copy Parameters to the Context

Initialize the newly created context with the codec parameters found in the stream container using avcodec_parameters_to_context():

if (avcodec_parameters_to_context(codec_ctx, video_stream->codecpar) < 0) {
    // Handle error: Failed to copy parameters
    avcodec_free_context(&codec_ctx);
    return -1;
}

4. Open the Codec

Initialize the decoding context to prepare it for receiving packets:

if (avcodec_open2(codec_ctx, decoder, NULL) < 0) {
    // Handle error: Could not open codec
    avcodec_free_context(&codec_ctx);
    return -1;
}

Complete Example

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

AVCodecContext* create_video_decoder_context(AVFormatContext *fmt_ctx) {
    const AVCodec *decoder = NULL;
    
    int stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
    if (stream_idx < 0) {
        return NULL;
    }

    AVCodecContext *codec_ctx = avcodec_alloc_context3(decoder);
    if (!codec_ctx) {
        return NULL;
    }

    if (avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[stream_idx]->codecpar) < 0) {
        avcodec_free_context(&codec_ctx);
        return NULL;
    }

    if (avcodec_open2(codec_ctx, decoder, NULL) < 0) {
        avcodec_free_context(&codec_ctx);
        return NULL;
    }

    return codec_ctx;
}

Cleanup

When finished decoding, free the allocated context using avcodec_free_context() to release memory and associated resources:

avcodec_free_context(&codec_ctx);