FFMPEG によるオーディオのリサンプリング

準備する

1.ffmpeg4.4

2.sdl2

3. 生のオーディオ PCM データ

リサンプリングプロセス

1. 入力オーディオパラメータと出力オーディオパラメータを設定します

2. 設定されたパラメータに従って SwrContent コンテキストを初期化します。

3. 入力バッファを作成し、入力オーディオ パラメータ (サンプリング レート、チャンネル数、サンプル ビット深度) に従ってスペースを適用し、入力オーディオ データを保存するためのデフォルト データを入力します。

4. 出力バッファを作成し、出力オーディオ パラメータ (サンプリング レート、チャネル番号、サンプル ビット深度) に従ってスペースを適用し、デフォルト データを入力して、リサンプリングされたデータを保存します。

5. PCM データを読み取ります。各読み取りのサイズは入力バッファーのサイズと同じです。

6. リサンプリングを実行する swr_convert

7. 出力バッファを再生のために SDL2 オーディオ コールバック バッファにコピーするか、ファイルに直接書き込むか、テストのために ffplay を使用するか、フレームにカプセル化してオーディオ エンコーダ (aac など) に送信して保存します。エンコード後。

キーコード

リサンプリングパラメータを設定し、SWr_Content構造体を初期化する


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
	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");
	}

ファイルを読み込んでリサンプルする

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);

ソースコードの共有

#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;
}

おすすめ

転載: blog.csdn.net/yunxiaobaobei/article/details/130779928