ffmpeg音频重采样的实现

音频重采样的基本概念

不同的⾳源有不同的格式,采样率等,所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。

音频重采样的封装

重采样的参数
typedef struct audio_resampler_params {
    // 输入参数
    enum AVSampleFormat src_sample_fmt;
    int src_sample_rate;
    uint64_t src_channel_layout;
    // 输出参数
    enum AVSampleFormat dst_sample_fmt;
    int dst_sample_rate;
    uint64_t dst_channel_layout;
}audio_resampler_params_t;

封装的重采样器
typedef struct audio_resampler {
    struct SwrContext *swr_ctx;     // 重采样上下文
    audio_resampler_params_t resampler_params;  // 重采样的设置参数
    int is_fifo_only;       // 不需要进行重采样,只需要缓存到 audio_fifo
    int is_flushed;         // flush的时候使用
    AVAudioFifo *audio_fifo;    // 采样点的缓存
    int64_t in_start_pts;          // 进入的起始pts
    int64_t in_last_pts;           // 保存上一次的pts时间戳
    int64_t out_start_pts;          // 输出的pts
    int64_t out_cur_pts;            // 当前pts

    uint8_t **resampled_data;   // 用来缓存重采样后的数据
    int resampled_data_size;    // 重采样后的采样数
    int src_channels;           // 输入的通道数
    int dst_channels;           // 输出通道数
    int64_t total_resampled_num;    // 统计总共的重采样点数
}audio_resampler_t;

音频重采样的基本流程

  1. 分配重采样上下文,设置重采样的源参数和目的参数,初始化重采样上下文。
/* alloc*/
    audio_resampler->swr_ctx = swr_alloc();
/* set options */
    av_opt_set_sample_fmt(audio_resampler->swr_ctx, "in_sample_fmt",      resampler_params.src_sample_fmt, 0);
    av_opt_set_int(audio_resampler->swr_ctx,        "in_channel_layout",  resampler_params.src_channel_layout, 0);
    av_opt_set_int(audio_resampler->swr_ctx,        "in_sample_rate",     resampler_params.src_sample_rate, 0);
    av_opt_set_sample_fmt(audio_resampler->swr_ctx, "out_sample_fmt",     resampler_params.dst_sample_fmt, 0);
    av_opt_set_int(audio_resampler->swr_ctx,        "out_channel_layout", resampler_params.dst_channel_layout, 0);
    av_opt_set_int(audio_resampler->swr_ctx,        "out_sample_rate",    resampler_params.dst_sample_rate, 0);
/* initialize the resampling context */
    ret = swr_init(audio_resampler->swr_ctx);
  1. 分配audio fifo。
  audio_resampler->audio_fifo = av_audio_fifo_alloc(resampler_params.dst_sample_fmt, audio_resampler->dst_channels, 1);
  1. 通过输入与输出的通道数量、采样点、采样格式,来分配分配输入源内存空间和输出内存空间。
  src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
  // 给输入源分配内存空间
  av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels, src_nb_samples, src_sample_fmt, 0);

  dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
  // 分配输出缓存内存
  av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels, dst_nb_samples, dst_sample_fmt, 0);
  1. 开始循环
    a) 采集输入源,产生一帧源音频数据。
    b) 发送音频:将音频帧进行重采样,并将数据写入audio fifo。
    int nb_samples = swr_convert(resampler->swr_ctx, resampler->resampled_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);
    int ret_size = av_audio_fifo_write(resampler->audio_fifo, (void **)resampler->resampled_data, nb_samples);

c) 接收音频:从audio fifo中读取一帧数据并写入目标缓存。

    av_audio_fifo_read(resampler->audio_fifo, (void **)frame->data, nb_samples);

5.冲刷缓冲区,以及进行内存释放。

音频重采样的官方示例

https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/resample_audio.c

你可能感兴趣的:(ffmpeg,音视频)