How to Resample Audio Using FFmpeg libswresample
This article provides a practical, step-by-step guide on how to
programmatically resample audio using FFmpeg’s
libswresample library in C or C++. You will learn how to
set up the resampling context, configure input and output
parameters—such as sample rate, channel layout, and sample
format—allocate the necessary data buffers, perform the conversion, and
properly clean up resources to avoid memory leaks.
Step 1: Initialize the Resampling Context
The core of libswresample is the
SwrContext. To set it up, you define your input and output
audio parameters (sample rate, channel layout, and sample format) and
allocate the context using swr_alloc_set_opts2.
#include <libswresample/swresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/pixfmt.h>
SwrContext *swr_ctx = NULL;
int ret;
// Define input parameters
AVChannelLayout in_ch_layout = AV_CHANNEL_LAYOUT_STEREO;
enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_FLTP; // Float planar
int in_sample_rate = 48000;
// Define output parameters (e.g., converting to CD quality)
AVChannelLayout out_ch_layout = AV_CHANNEL_LAYOUT_STEREO;
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; // Signed 16-bit packed
int out_sample_rate = 44100;
// Allocate the context
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) {
fprintf(stderr, "Could not allocate resampler context\n");
// Handle error
}Step 2: Initialize the Context
Once the options are assigned to the context, you must initialize it
using swr_init before performing any conversion.
ret = swr_init(swr_ctx);
if (ret < 0) {
fprintf(stderr, "Failed to initialize the resampling context\n");
swr_free(&swr_ctx);
// Handle error
}Step 3: Calculate and Allocate Output Buffers
Because of sample rate conversion, the number of output samples might
differ from the number of input samples. You must calculate the upper
bound of the output samples, taking internal buffering delays into
account using swr_get_delay.
int in_samples = 1024; // Number of input samples per channel
uint8_t **src_data = NULL; // Your input audio data pointers
uint8_t **dst_data = NULL; // Target resampled audio data pointers
int src_linesize, dst_linesize;
// Calculate max destination samples
int64_t delay = swr_get_delay(swr_ctx, in_sample_rate);
int out_samples = av_rescale_rnd(delay + in_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);
// Allocate destination samples buffer
ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize,
out_ch_layout.nb_channels,
out_samples, out_sample_fmt, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate destination samples\n");
// Handle error
}Step 4: Perform the Conversion
With the buffers allocated, pass the input and output pointers to
swr_convert. This function returns the exact number of
output samples written per channel.
// Perform the actual conversion
int converted_samples = swr_convert(swr_ctx,
dst_data, out_samples,
(const uint8_t **)src_data, in_samples);
if (converted_samples < 0) {
fprintf(stderr, "Error while converting\n");
// Handle error
}
// dst_data now contains 'converted_samples' of resampled audioStep 5: Flush Latent Samples (Optional)
At the end of your audio stream, the resampler may still hold
buffered samples internally. To flush these remaining samples, call
swr_convert with the input parameters set to
NULL and 0.
int flushed_samples = swr_convert(swr_ctx,
dst_data, out_samples,
NULL, 0);Step 6: Clean Up Resources
To avoid memory leaks, free the allocated sample buffers and the resampling context when you are finished.
if (dst_data) {
av_freep(&dst_data[0]);
av_freep(&dst_data);
}
swr_free(&swr_ctx);