Audio Resampling with FFmpeg libswresample
This guide demonstrates how to programmatically resample, convert
channel layouts, and change sample formats of audio data using FFmpeg's
libswresample library in C or C++. You will learn how to
allocate and configure an SwrContext, calculate the
necessary output buffer sizes, execute the conversion loop, flush
remaining buffered samples, and safely release allocated resources.
1. Prerequisites and Key Concepts
libswresample performs three core operations on PCM
audio data:
- Sample rate conversion: Adjusting the frequency (e.g., 44.1 kHz to 48 kHz).
- Format conversion: Converting bit depths and packing styles (e.g., 16-bit signed integer interleaved to 32-bit float planar).
- Channel rematrixing: Changing channel counts and layouts (e.g., 5.1 surround sound to stereo).
Modern versions of FFmpeg (version 5.1 and newer) use the
AVChannelLayout structure instead of legacy uint64 channel
bitmasks, and use swr_alloc_set_opts2() for
initialization.
2. Step-by-Step Workflow
Step 1: Initialize the SwrContext
Allocate and configure the resampler context by defining your input and output audio properties:
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
struct SwrContext *swr_ctx = NULL;
// Define input parameters (e.g., Stereo, 44100Hz, S16 interleaved)
AVChannelLayout in_ch_layout = AV_CHANNEL_LAYOUT_STEREO;
enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_S16;
int in_sample_rate = 44100;
// Define output parameters (e.g., 5.1 Surround, 48000Hz, Float planar)
AVChannelLayout out_ch_layout = AV_CHANNEL_LAYOUT_5POINT1;
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_FLTP;
int out_sample_rate = 48000;
// Allocate and set options
int ret = swr_alloc_set_opts2(&swr_ctx,
&out_ch_layout, out_sample_fmt, out_sample_rate,
&in_ch_layout, in_sample_fmt, in_sample_rate,
0, NULL);
if (ret < 0 || !swr_ctx) {
// Handle error
}
// Initialize the resampling context
if (swr_init(swr_ctx) < 0) {
swr_free(&swr_ctx);
// Handle error
}Step 2: Allocate Output Buffers
Because resampling changes sample rates, input and output sample
counts will differ. You must determine the maximum number of output
samples that can be generated using swr_get_out_samples()
to prevent buffer overflows:
int in_nb_samples = 1024; // Number of input samples per channel
uint8_t **out_data = NULL;
int out_linesize;
// Compute upper-bound output sample count
int max_out_samples = swr_get_out_samples(swr_ctx, in_nb_samples);
// Allocate output audio buffers
ret = av_samples_alloc_array_and_samples(&out_data, &out_linesize,
out_ch_layout.nb_channels,
max_out_samples,
out_sample_fmt, 0);
if (ret < 0) {
// Handle allocation error
}Step 3: Perform the Conversion
Pass your input buffer to swr_convert(). For planar
formats, each pointer in the array points to a distinct channel plane.
For interleaved formats, all data is in data[0].
// Perform resampling
int converted_samples = swr_convert(swr_ctx,
out_data, max_out_samples,
(const uint8_t **)in_data, in_nb_samples);
if (converted_samples < 0) {
// Handle conversion error
}
// Write or process converted_samples from out_data...Step 4: Flush Cached Samples
Resampling algorithms use internal filters that introduce algorithmic
delay, keeping some samples inside the resampler. When you reach the end
of the input audio stream, flush the remaining samples by passing
NULL for the input pointers and 0 for input
sample count:
int flushed_samples;
do {
flushed_samples = swr_convert(swr_ctx, out_data, max_out_samples, NULL, 0);
if (flushed_samples > 0) {
// Write or process flushed_samples from out_data...
}
} while (flushed_samples > 0);Step 5: Clean Up
Always free your allocated buffers and context once processing is complete:
if (out_data) {
av_freep(&out_data[0]);
av_freep(&out_data);
}
swr_free(&swr_ctx);Summary Checklist
- Call
swr_alloc_set_opts2()with target and source configurations. - Initialize with
swr_init(). - Query needed buffer size with
swr_get_out_samples(). - Run
swr_convert()on incoming audio chunks. - Pass
NULLtoswr_convert()at EOF to drain buffered data. - Deallocate memory with
av_freep()andswr_free().