Audio resampling with FFMPEG

Prepare

1. ffmpeg 4.4

2. sdl2

3. A piece of raw audio PCM data

resampling process

1. Set input audio parameters and output audio parameters

2. Initialize the SwrContent context according to the set parameters

3. Create an input buffer, apply for space according to the input audio parameters (sampling rate, number of channels, sample bit depth), and fill in the default data to store the input audio data

4. Create an output buffer, apply for space according to the output audio parameters (sampling rate, channel number, sample bit depth), fill in the default data, and store the resampled data

5. Read PCM data, the size of each read is equal to the size of the input buffer

6. Perform resampling swr_convert

7. Copy the output buffer to the SDL2 audio callback buffer for playback, or write it directly to a file, use ffplay for testing, or encapsulate it into a Frame and send it to an audio encoder (such as aac), and save it after encoding.

key code

Set resampling parameters and initialize SWr_Content structure


struct SwrContext* swr_ctx;

swr_ctx = swr_alloc_set_opts(nullptr,
		AV_CH_LAYOUT_MONO, //输出通道
		AV_SAMPLE_FMT_S16, //输出样本格式
		44100, //输出采样率
		AV_CH_LAYOUT_STEREO,  //输入通道
		AV_SAMPLE_FMT_FLT,  //输入样本格式
		44100, //输入采样率
		0, nullptr); 

	swr_init(swr_ctx);

I/O buffer creation

	//输入数据buffer
	uint8_t** pcm_buffer;
	int src_linesize;
	int src_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
	int ret = av_samples_alloc_array_and_samples(&pcm_buffer, &src_linesize, src_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_FLT, 0);
	if (ret < 0) {
		fprintf(stderr, "Could not allocate source samples\n");	
	}

	//输出数据buffer
	uint8_t** out_buffer;
	int dst_linesize;
	int dst_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
	ret = av_samples_alloc_array_and_samples(&out_buffer, &dst_linesize, dst_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_S16, 0);
	if (ret < 0) {
		fprintf(stderr, "Could not allocate source samples\n");
	}

read file and resample

readcount = fread((char *)pcm_buffer[0], 1, src_linesize, fp);

data_count += readcount;
printf("   Now Playing %10d KBytes data.  %d \n", data_count / 1024, readcount);
		
swr_convert(swr_ctx, out_buffer, frame_nb_samples, (const uint8_t**)pcm_buffer, frame_nb_samples);

Source code sharing

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sdl.h"

extern "C"
{
	#include <libavutil/opt.h>
	#include <libavutil/channel_layout.h>
	#include <libavutil/samplefmt.h>
	#include <libswresample/swresample.h>
}

static  Uint32  audio_len;
static  Uint8* audio_pos;
int frame_nb_samples = 1024; //一帧数据样本数
struct SwrContext* swr_ctx;


void  fill_audio_pcm(void* udata, Uint8* stream, int len) 
{
	SDL_memset(stream, 0, len);

	if (audio_len == 0)
		return;
	len = (len > audio_len ? audio_len : len);

	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
	audio_pos += len;
	audio_len -= len;
}

int main(int argc, char* argv[])
{
	if (SDL_Init(SDL_INIT_AUDIO || SDL_INIT_TIMER))
	{
		printf("SDL init error\n");
		return -1;
	}

	swr_ctx = swr_alloc_set_opts(nullptr,
		AV_CH_LAYOUT_MONO, //输出通道
		AV_SAMPLE_FMT_S16, //输出样本格式
		44100, //输出采样率
		AV_CH_LAYOUT_STEREO,  //输入通道
		AV_SAMPLE_FMT_FLT,  //输入样本格式
		44100, //输入采样率
		0, nullptr); 

	swr_init(swr_ctx);

	//SDL_AudioSpec
	SDL_AudioSpec wanted_spec;
	wanted_spec.freq = 44100;
	wanted_spec.format = AUDIO_F32; //AUDIO_S16LSB; //AUDIO_F32;
	wanted_spec.channels = 2;
	wanted_spec.silence = 0;
	wanted_spec.samples = frame_nb_samples;
	wanted_spec.callback = fill_audio_pcm;

	if (SDL_OpenAudio(&wanted_spec, NULL) < 0) {
		printf("can't open audio.\n");
		return -1;
	}
	//Play
	SDL_PauseAudio(0);
	
	//输入数据buffer
	uint8_t** pcm_buffer;
	int src_linesize;
	int src_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
	int ret = av_samples_alloc_array_and_samples(&pcm_buffer, &src_linesize, src_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_FLT, 0);
	if (ret < 0) {
		fprintf(stderr, "Could not allocate source samples\n");	
	}

	//输出数据buffer
	uint8_t** out_buffer;
	int dst_linesize;
	int dst_nb_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
	ret = av_samples_alloc_array_and_samples(&out_buffer, &dst_linesize, dst_nb_channels, frame_nb_samples, AV_SAMPLE_FMT_S16, 0);
	if (ret < 0) {
		fprintf(stderr, "Could not allocate source samples\n");
	}

	FILE* fp = nullptr;
	fopen_s(&fp, "D:/工程/音视频分析/source/f32le.pcm", "rb+");
	if (fp == NULL) {
		printf("cannot open this file\n");
		return -1;
	}
	int readcount = -1;
	int data_count = 0;
	while (!feof(fp)) 
	{
		readcount = fread((char *)pcm_buffer[0], 1, src_linesize, fp);

		data_count += readcount;
		printf("   Now Playing %10d KBytes data.  %d \n", data_count / 1024, readcount);
		
		swr_convert(swr_ctx, out_buffer, frame_nb_samples, (const uint8_t**)pcm_buffer, frame_nb_samples);

		//Set audio buffer (PCM data)
		audio_len = dst_linesize; 
		audio_pos =  (Uint8*)out_buffer[0]; //(Uint8*)pcm_buffer[0];

		while (audio_len > 0)
			SDL_Delay(1);
		
	}

	if (pcm_buffer)
		av_freep(&pcm_buffer[0]);
	av_freep(&pcm_buffer);

	if (out_buffer)
		av_freep(&out_buffer[0]);
	av_freep(&out_buffer);

	swr_free(&swr_ctx);

	fclose(fp);
	SDL_Quit();

	return 0;
}

Guess you like

Origin blog.csdn.net/yunxiaobaobei/article/details/130779928