FFmpeg学习—ffmpeg 利用 swr_convert 函数将AV_SAMPLE_FMT_S16 转 AV_SAMPLE_FMT_FLTP

在Android 平台下利用AudioRecord 录制音频数据时基于 ENCODING_PCM_16BIT 进行采样,然后在利用ffmpeg 进行编码成aac格式的音频文件,由于最新ffmpeg 库的sample_fmt必须以AV_SAMPLE_FMT_FLTP这种方式进行存储,而ENCODING_PCM_16BIT 是AV_SAMPLE_FMT_S16格式的。如果是单声道的话两者区别不大,都可以存在AVFrame->data[0] 里面,只是AV_SAMPLE_FMT_FLTP是以浮点数的方式存储,后者是以有符号整形16位存贮的。如果是双声道的话二者的区别就比较大了。AV_SAMPLE_FMT_S16的存贮方式如下图:

AV_SAMPLE_FMT_FLTP的存储方式如下图:

AV_SAMPLE_FMT_S16是非平坦的,左右声道以LRLR....的方式连续的存在一个数组里面,AV_SAMPLE_FMT_FLTP是平坦的存贮方式,左右声道是分开存在两个数组里面的。

如何将Android 以 CHANNEL_IN_STEREO(双声道)  ENCODING_PCM_16BIT (AV_SAMPLE_FMT_S16) 录制方式用ffmpeg 用AV_SAMPLE_FMT_FLTP编码为aac音频文件呢?其实ffmepg 已经提供了这样的接口,就是swr_convert 函数,转换方式如下:

在android 里面初始化AudioRecord:

 

 minBufferSize = 4096;
 audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize);


其中minBufferSize 要设置为4096,因为ffmpeg 的frame_size 默认为1024,所以一次采样次数至少为1024次,由于一次采集两个声道,每个声道占两个字节,采集1024次就是1024*2*2=4096个字节,我开始做的时候没注意这个就一直不对。

 

swr_convert 函数的定义如下:

 

int swr_convert(struct SwrContext *s, 
				uint8_t **out, 
				int out_count,
                const uint8_t **in , 
				int in_count);

第一个参数是SwrContext 结构体,第二个参数是输出数据保存的地方,第三个参数是out的大小,第四个参数是输入数据就是要待转换的数据,第五个参数是输入数据采样的个数。

 

SwrContext 的初始化:

 

SwrContext      *swr;
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout",  AV_CH_LAYOUT_STEREO, 0);
    av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO,  0);
    av_opt_set_int(swr, "in_sample_rate",     16000, 0);
    av_opt_set_int(swr, "out_sample_rate",    16000, 0);
    av_opt_set_sample_fmt(swr, "in_sample_fmt",  AV_SAMPLE_FMT_S16, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);
    swr_init(swr);


定义输出数据保存的数组:

 

 

 uint8_t *outs[2];
    outs[0]=(uint8_t *)malloc(len);//len 为4096
    outs[1]=(uint8_t *)malloc(len);


进行转换

 

 

uint8_t* srcBuf = (uint8_t*) (*env)->GetByteArrayElements(env, pcmData, 0);//pcmData是android 传下来的的pcm 数据,为4096个字节,1024次采样。
int count=swr_convert(swr,&outs,len*4,&srcBuf,len/4);//len 为4096
audioFrame->data[0] =(uint8_t*)outs[0];//audioFrame 是VFrame
 audioFrame->data[1] =(uint8_t*)outs[1];

 

 

 

如果是单声道转的话

AudioRecord 的初始化如下:

 

minBufferSize = 2048;//1024*2
 audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize);

 

 

 

SwrContext 的初始化:

 

SwrContext      *swr;
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout",  AV_CH_LAYOUT_MONO, 0);
    av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO,  0);
    av_opt_set_int(swr, "in_sample_rate",     16000, 0);
    av_opt_set_int(swr, "out_sample_rate",    16000, 0);
    av_opt_set_sample_fmt(swr, "in_sample_fmt",  AV_SAMPLE_FMT_S16, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);
    swr_init(swr);

 

定义输出数据保存的数组:

 

 

 uint8_t *outs[1];
    outs[0]=(uint8_t *)malloc(len*2);//len 为2048

 

进行转换

 

 

 

uint8_t* srcBuf = (uint8_t*) (*env)->GetByteArrayElements(env, pcmData, 0);//pcmData是android 传下来的的pcm 数据,为2048个字节,1024次采样。
int count=swr_convert(swr,&outs,len*2,&srcBuf,len/2);//len 为2048
audioFrame->data[0] =(uint8_t*)outs[0];//audioFrame 是VFrame

 

转换例子

 

https://github.com/XIAIBIANCHENG/OggRecord/tree/master

`swr_convert` 是 FFmpeg 库中的一个函数,用于在不同的音频格式之间进行重采样换。如果你想在 C++ 程序中调用 `swr_convert` 来处理 WAV 格式的音频并播放它,你需要首先确保你已经正确安装了 FFmpeg 库,并且配置了相应的编译环境。 在 C++ 中使用 `swr_convert` 处理并播放 WAV 格式的音频大致可以分为以下几个步骤: 1. 初始化源音频流和目标音频流的参数(比如采样率、通道数、采样格式等)。 2. 创建一个音频重采样上下文 `SwrContext`。 3. 使用 `swr_alloc_set_opts` 初始化重采样上下文,并设置源和目标的参数。 4. 打开源音频文件,读取源音频数据。 5. 使用 `swr_convert` 进行重采样换。 6. 播放换后的音频数据,这通常需要使用 FFmpeg 的其他音视频处理函数或集成第三方库,如 ALSA、PulseAudio 等,或者将数据写入文件进行播放。 7. 清理资源,释放重采样上下文和关闭音频文件。 以下是使用 `swr_convert` 的一个简化的示例代码框架: ```cpp #include <libswresample/swresample.h> int main() { // 初始化源音频流和目标音频流参数 AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16; // 源音频采样格式 int src_sample_rate = 44100; // 源音频采样率 int src_channels = 2; // 源音频通道数 AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_FLTP; // 目标音频采样格式 int dst_sample_rate = 44100; // 目标音频采样率 int dst_channels = 2; // 目标音频通道数 // 创建重采样上下文 SwrContext *swr_ctx = swr_alloc_set_opts(NULL, dst_channels, dst_sample_fmt, dst_sample_rate, src_channels, src_sample_fmt, src_sample_rate, 0, NULL); if (!swr_ctx) { // 错误处理 } // 初始化重采样上下文 swr_init(swr_ctx); // 读取源音频数据,进行重采样换,并播放处理后的音频数据 // ... // 清理资源 swr_free(&swr_ctx); return 0; } ``` 请注意,这只是一个非常基础的示例,实际使用时你需要添加更多的代码来处理文件读取、错误检查、数据处理以及音频播放等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值