Skip to main content
This example shows how to encode audio data using libavcodec. It generates a synthetic audio signal (a sine wave) and encodes it to MP2 format.

Overview

The example creates a 440Hz tone and encodes it to an MP2 audio file. It demonstrates:
  • Finding and configuring an audio encoder
  • Selecting appropriate encoder parameters
  • Generating audio samples
  • The send/receive encoding pattern
  • Flushing the encoder

Key Components

Encoder Setup

/* find the MP2 encoder */
codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
if (!codec) {
    fprintf(stderr, "Codec not found\n");
    exit(1);
}

c = avcodec_alloc_context3(codec);
if (!c) {
    fprintf(stderr, "Could not allocate audio codec context\n");
    exit(1);
}

/* put sample parameters */
c->bit_rate = 64000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->sample_rate = select_sample_rate(codec);
ret = select_channel_layout(codec, &c->ch_layout);

if (avcodec_open2(c, codec, NULL) < 0) {
    fprintf(stderr, "Could not open codec\n");
    exit(1);
}

Selecting Encoder Parameters

Helper functions choose compatible parameters:
/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{
    const enum AVSampleFormat *p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

/* just pick the highest supported samplerate */
static int select_sample_rate(const AVCodec *codec)
{
    const int *p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
            best_samplerate = *p;
        p++;
    }
    return best_samplerate;
}

Frame Allocation

/* frame containing input raw audio */
frame = av_frame_alloc();
if (!frame) {
    fprintf(stderr, "Could not allocate audio frame\n");
    exit(1);
}

frame->nb_samples     = c->frame_size;
frame->format         = c->sample_fmt;
ret = av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
if (ret < 0)
    exit(1);

/* allocate the data buffers */
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
    fprintf(stderr, "Could not allocate audio data buffers\n");
    exit(1);
}

Encoding Function

static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *output)
{
    int ret;

    /* send the frame for encoding */
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending the frame to the encoder\n");
        exit(1);
    }

    /* read all the available output packets (in general there may be any
     * number of them */
    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error encoding audio frame\n");
            exit(1);
        }

        fwrite(pkt->data, 1, pkt->size, output);
        av_packet_unref(pkt);
    }
}

Generating Audio Samples

The example generates a sine wave:
/* encode a single tone sound */
t = 0;
tincr = 2 * M_PI * 440.0 / c->sample_rate;
for (i = 0; i < 200; i++) {
    /* make sure the frame is writable -- makes a copy if the encoder
     * kept a reference internally */
    ret = av_frame_make_writable(frame);
    if (ret < 0)
        exit(1);
    samples = (uint16_t*)frame->data[0];

    for (j = 0; j < c->frame_size; j++) {
        samples[2*j] = (int)(sin(t) * 10000);

        for (k = 1; k < c->ch_layout.nb_channels; k++)
            samples[2*j + k] = samples[2*j];
        t += tincr;
    }
    encode(c, frame, pkt, f);
}

Important Patterns

Frame Writability

Always ensure frames are writable before modification:
ret = av_frame_make_writable(frame);
if (ret < 0)
    exit(1);
This is critical because the encoder may keep references to frames.

Flushing

Flush the encoder by sending NULL:
/* flush the encoder */
encode(c, NULL, pkt, f);

Packet Management

Always unref packets after use:
av_packet_unref(pkt);

Channel Layout Selection

static int select_channel_layout(const AVCodec *codec, AVChannelLayout *dst)
{
    const AVChannelLayout *p, *best_ch_layout;
    int best_nb_channels   = 0;

    if (!codec->ch_layouts)
        return av_channel_layout_copy(dst, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO);

    p = codec->ch_layouts;
    while (p->nb_channels) {
        int nb_channels = p->nb_channels;

        if (nb_channels > best_nb_channels) {
            best_ch_layout   = p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return av_channel_layout_copy(dst, best_ch_layout);
}

Usage

./encode_audio output.mp2
Play the result:
ffplay output.mp2

Build docs developers (and LLMs) love