Setup FFmpeg Audio Resampler with swr_alloc_set_opts2

This guide demonstrates how to configure and initialize an audio resampling context using the modern swr_alloc_set_opts2 function in FFmpeg's libswresample library. You will learn how to define source and target audio parameters using the modern AVChannelLayout API, allocate the SwrContext, initialize the resampler, and manage resources safely with proper error checking.

Understanding swr_alloc_set_opts2

In modern FFmpeg versions (5.1+), the legacy swr_alloc_set_opts function was deprecated in favor of swr_alloc_set_opts2. The updated function works with the AVChannelLayout struct rather than legacy 64-bit bitmasks and returns standard FFmpeg error codes directly.

The function signature is:

int swr_alloc_set_opts2(struct SwrContext **ps,
                        const AVChannelLayout *out_ch_layout,
                        enum AVSampleFormat out_sample_fmt,
                        int out_sample_rate,
                        const AVChannelLayout *in_ch_layout,
                        enum AVSampleFormat in_sample_fmt,
                        int in_sample_rate,
                        int log_offset,
                        void *log_ctx);

Implementation Steps

  1. Define Source and Destination Layouts: Initialize the AVChannelLayout structures using av_channel_layout_default or by copying an existing layout from an AVCodecContext.
  2. Allocate the Resampler: Pass the address of your SwrContext* pointer to swr_alloc_set_opts2 along with the source and target layouts, sample formats, and sample rates.
  3. Initialize the Context: Finalize the setup by calling swr_init().
  4. Cleanup: Free the resampler with swr_free() and release any allocated layouts using av_channel_layout_uninit().

Code Example

Below is a complete, minimal C program demonstrating how to set up an audio resampler from a 48 kHz stereo float configuration to a 44.1 kHz mono 16-bit signed integer configuration:

#include <stdio.h>
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <libavutil/error.h>
#include <libswresample/swresample.h>

int main(void) {
    int ret = 0;
    SwrContext *swr_ctx = NULL;

    // Define channel layouts
    AVChannelLayout in_layout = AV_CHANNEL_LAYOUT_STEREO;
    AVChannelLayout out_layout = AV_CHANNEL_LAYOUT_MONO;

    // Define sample formats and rates
    enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_FLTP; // Planar float
    int in_sample_rate = 48000;

    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;  // Signed 16-bit integer
    int out_sample_rate = 44100;

    // Allocate and configure the resampler context
    ret = swr_alloc_set_opts2(
        &swr_ctx,
        &out_layout,
        out_sample_fmt,
        out_sample_rate,
        &in_layout,
        in_sample_fmt,
        in_sample_rate,
        0,
        NULL
    );

    if (ret < 0) {
        char err_buf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, err_buf, sizeof(err_buf));
        fprintf(stderr, "Failed to allocate resampler: %s\n", err_buf);
        return ret;
    }

    // Initialize the resampling context
    ret = swr_init(swr_ctx);
    if (ret < 0) {
        char err_buf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, err_buf, sizeof(err_buf));
        fprintf(stderr, "Failed to initialize resampler: %s\n", err_buf);
        swr_free(&swr_ctx);
        return ret;
    }

    printf("Audio resampler successfully initialized.\n");

    // Free the context when finished
    swr_free(&swr_ctx);

    // Uninitialize layouts if they dynamically allocated memory
    av_channel_layout_uninit(&in_layout);
    av_channel_layout_uninit(&out_layout);

    return 0;
}

Key Considerations

  • Layout Initialization: Predefined macros like AV_CHANNEL_LAYOUT_STEREO do not allocate dynamic memory, but if you create custom layouts using av_channel_layout_from_string or av_channel_layout_copy, always call av_channel_layout_uninit on them to avoid memory leaks.
  • Reconfiguration: If swr_ctx already points to an allocated resampler, swr_alloc_set_opts2 reconfigures the existing context instead of allocating a new one, but you must call swr_init() again before processing new audio frames.