使用FFmpeg将S16格式音频数据重采样为FLTP格式

这段代码展示了如何使用libavutil和libswresample库将音频数据从AV_SAMPLE_FMT_S16格式重采样转换为AV_SAMPLE_FMT_FLTP格式。程序从指定的输入文件读取音频数据,进行重采样,并将结果写入输出文件。注意,该代码可能不包含所有必要的错误检查和边界条件处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码对一些数据没做判断,仅仅是做个备忘!请谨慎参考!

#include <libavutil/opt.h>
#include <libavutil/samplefmt.h>
#include <libswresample/swresample.h>
#include <stdio.h>

#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h"
#include "libswresample/swresample.h"

/**
 * @brief 音频重采样 AV_SAMPLE_FMT_S16-->AV_SAMPLE_FMT_FLTP
 * @param argc
 * @param argv
 * @return
 */
int main(int argc, char **argv) {
  SwrContext *swr_context = NULL;
  uint8_t *in_buf = NULL;
  uint8_t **in_data = NULL;
  int in_size = 0;
  uint8_t **out_data = NULL;
  int out_size = 0;
  int line_size = 0;
  int in_nb_samples = 1024;
  int in_channel_count = 2;
  int out_channel_count = 2;
  int64_t in_ch_layout = AV_CH_LAYOUT_STEREO;
  int64_t out_ch_layout = AV_CH_LAYOUT_STEREO;
  int in_sample_rate = 44100, out_sample_rate = 44100;
  int out_nb_samples = 0, max_out_nb_samples = 0;
  enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_S16;
  enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_FLTP;
  FILE *in_file;
  FILE *out_file;
  int read_size;
  int ret;

  in_file = fopen(argv[1], "rb");
  out_file = fopen(argv[2], "wb");
  swr_context = swr_alloc();
  if (!swr_context) {
    printf("error 1\n");
    exit(1);
  }
  av_opt_set_int(swr_context, "in_sample_rate", in_sample_rate, 0);
  av_opt_set_int(swr_context, "in_channel_layout", in_ch_layout, 0);
  av_opt_set_sample_fmt(swr_context, "in_sample_fmt", in_sample_fmt, 0);
  av_opt_set_int(swr_context, "out_sample_rate", out_sample_rate, 0);
  av_opt_set_int(swr_context, "out_channel_layout", out_ch_layout, 0);
  av_opt_set_sample_fmt(swr_context, "out_sample_fmt", out_sample_fmt, 0);
  ret = swr_init(swr_context);
  if (ret < 0) {
    printf("error 2\n");
    exit(1);
  }
  ret = av_samples_alloc_array_and_samples(&in_data, &in_size, in_channel_count,
                                           in_nb_samples, in_sample_fmt, 0);
  if (ret < 0) {
    printf("error 6\n");
    exit(1);
  }

  out_nb_samples = max_out_nb_samples = av_rescale_rnd(
      in_nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);

  ret = av_samples_alloc_array_and_samples(&out_data, &out_size,
                                           out_channel_count, out_nb_samples,
                                           out_sample_fmt, 0);
  if (ret < 0) {
    printf("error 7\n");
    exit(1);
  }
  //一次重采样多少数据
  int bytes_per_frame = av_samples_get_buffer_size(
      &line_size, in_channel_count, in_nb_samples, in_sample_fmt, 0);
  in_buf = av_malloc(bytes_per_frame);
  while ((read_size = fread(in_buf, 1, bytes_per_frame, in_file)) ==
         bytes_per_frame) {
    ret = av_samples_fill_arrays(in_data, &in_size, in_buf, in_channel_count,
                                 in_nb_samples, in_sample_fmt, 0);
    if (ret < 0) {
      printf("error 3\n");
      exit(1);
    }

    int64_t delay = swr_get_delay(swr_context, in_sample_rate);
    out_nb_samples = av_rescale_rnd(in_nb_samples + delay, out_sample_rate,
                                    in_sample_rate, AV_ROUND_UP);
    if (out_nb_samples > max_out_nb_samples) {
      av_freep(&out_data[0]);
      av_freep(&out_data[1]);
      ret = av_samples_alloc(out_data, out_size, out_channel_count,
                             out_nb_samples, out_sample_fmt, 0);
      if (ret < 0) break;
      max_out_nb_samples = out_nb_samples;
    }
    printf("out_nb_samples:%i\n", out_nb_samples);

    ret = swr_convert(swr_context, out_data, out_nb_samples,
                      (const uint8_t **)in_data, in_nb_samples);
    int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP);
    // FLTP写成packeted样式
    //    for (int i = 0; i < ret; i++) {
    //      for (int j = 0; j < out_channel_count; j++) {
    //        fwrite(out_data[j] + i * bytes_per_sample, 1, bytes_per_sample,
    //               out_file);
    //      }
    //    }
    // FLTP写成planar样式
    int each_planr_size =
        bytes_per_sample * ret;
    for (int j = 0; j < out_channel_count; j++) {
      fwrite(out_data[j], 1, each_planr_size, out_file);
    }
  }
end:
  fclose(in_file);
  fclose(out_file);
  av_freep(&in_buf);
  av_freep(&in_data[0]);
  av_freep(&in_data);
  av_freep(&out_data[0]);
  av_freep(&out_data[1]);
  av_freep(&out_data);
  swr_free(&swr_context);
  printf("Hello World!\n");
  return 0;
}

 

### 使用FFmpeg进行PCM音频重采样的方法 对于将PCM音频文件从48kHz(即每秒48000个样本)转换为44.1kHz(即每秒44100个样本),可以通过命令行工具`ffmpeg`轻松实现这一过程。具体操作如下: #### 命令行方式 可以直接利用`ffmpeg`命令来完成此任务,无需编写额外的程序代码。下面给出了一条简单的命令用于执行上述需求的操作。 ```bash ffmpeg -i input.wav -ar 44100 output.wav ``` 这条指令中的`-i input.wav`指定了待处理的源文件路径;而`-ar 44100`则设定了目标音频的采样率为44.1kHz;最后指定输出文件名为`output.wav`[^1]。 如果希望进一步调整其他属性比如声道数量或改变位深,则可以在命令中加入更多选项。例如要同时更改声道数目以及采用不同的编码格式,可参照以下例子: ```bash ffmpeg -i input.wav -ar 44100 -ac 2 -sample_fmt s16 output.wav ``` 这里增加了两个新的参数:`-ac 2`表示双声道立体声输出,`-sample_fmt s16`意味着使用16比特整型作为样本格式[^2]。 #### 编程接口调用 当需要在应用程序内部集成此类功能时,可以借助于FFmpeg库提供的API来进行更灵活的操作。以下是基于C++的一个简单实例片段展示如何创建一个SwrContext对象并配置其参数以准备进行重采样工作。 ```cpp extern "C" { #include <libswresample/swresample.h> } struct SwrContext *swr_ctx; // 初始化上下文,并设定输入输出参数 swr_ctx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, /* 输出布局 */ AV_SAMPLE_FMT_S16, /* 输出样本格式 */ 44100, /* 输出采样率 */ AV_CH_LAYOUT_MONO, /* 输入布局 */ AV_SAMPLE_FMT_FLTP, /* 输入样本格式 */ 48000, /* 输入采样率 */ 0, NULL); if (!swr_ctx || swr_init(swr_ctx) < 0){ fprintf(stderr,"Could not initialize the resampling context\n"); exit(1); } ``` 这段代码展示了怎样构建一个能够把单声道浮点型PCM流转换成双声道短整形PCM流的同时降低采样频率至44.1kHz的软件重采样器实例[^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值