FFmpeg Audio格式转换

在FFmpeg中进行音频的格式转换主要有三个步骤。

1、实例化SwrContext,并设置转换所需的参数:通道数量、channel layout、sample rate

两种方式实例化。

  • 使用swr_alloc
SwrContext *swr = swr_alloc();
av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 48000, 0);
av_opt_set_int(swr, "out_sample_rate", 44100, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
  • 使用 swr_alloc_set_opts
SwrContext *swr = swr_alloc_set_opts(NULL,  // we're allocating a new context
                        AV_CH_LAYOUT_STEREO,  // out_ch_layout
                        AV_SAMPLE_FMT_S16,    // out_sample_fmt
                        44100,                // out_sample_rate
                        AV_CH_LAYOUT_5POINT1, // in_ch_layout
                        AV_SAMPLE_FMT_FLTP,   // in_sample_fmt
                        48000,                // in_sample_rate
                        0,                    // log_offset
                        NULL);                // log_ctx

2、计算转换后的sample个数

计算公式为:src_nb_samples * dst_sample_rate / src_sample_rate

int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples, frame->sample_rate, frame->sample_rate, AVRounding(1));

函数av_rescale_rnd是按照指定的舍入方式计算a * b / c 。函数swr_get_delay得到输入sample和输出sample之间的延迟,并且其返回值的根据传入的第二个参数不同而不同。如果是输入的采样率,则返回值是输入sample个数;如果输入的是输出采样率,则返回值是输出sample个数。

3、调用 swr_convert进行转换

int nb = swr_convert(swr_ctx, &audio_buf, dst_nb_samples, (const uint8_t**)frame->data, frame->nb_samples);

 

SDL播放音频时的格式转换

1、首先使用avcodec_send_packetavcodec_receive_frame获取解码后的原始数据

int ret = avcodec_send_packet(aCodecCtx, &pkt);
ret = avcodec_receive_frame(aCodecCtx, frame);

2、设置通道数量和channel layout
在编码的时候有可能丢失通道数量或者channel layout ,这里根据获取的参数设置其默认值

if (frame->channels > 0 && frame->channel_layout == 0)
    frame->channel_layout = av_get_default_channel_layout(frame->channels);
else if (frame->channels == 0 && frame->channel_layout > 0)
    frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout)

如果channel layout未知(channel_layout = 0),根据通道数量获取其默认的channel layout;如同通道的数量未知,则根据其channel layout得到其通道数量。

3、设置输出格式

由于SDL2的sample格式不支持浮点型(FFmpeg中是支持的浮点型的),这里简单的设置输出格式为AV_SAMPLE_FMT_S16(16位有符号整型),输出的channel layout也
根据通道数量设置为默认值 dst_layout = av_get_default_channel_layout(frame->channels)(SDL2不支持planar格式)。实例化SwrContext

swr_ctx = swr_alloc_set_opts(nullptr, dst_layout, dst_format, frame->sample_rate,
		frame->channel_layout, (AVSampleFormat)frame->format, frame->sample_rate, 0, nullptr);
if (!swr_ctx || swr_init(swr_ctx) < 0)
    return -1;

在设置完参数后,一定要调用swr_init进行初始化。

4、转换

// 计算转换后的sample个数 a * b / c
int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples, frame->sample_rate, frame->sample_rate, AVRounding(1));
// 转换,返回值为转换后的sample个数
int nb = swr_convert(swr_ctx, &audio_buf, dst_nb_samples, (const uint8_t**)frame->data, frame->nb_samples);
data_size = frame->channels * nb * av_get_bytes_per_sample(dst_format);

最后data_size中保存的是转换的数据的字节数:通道数 * sample个数 * 每个sample的字节数。

https://github.com/brookicv/FFMPEG-study/blob/master/FFmpeg-playAudio.cpp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值