[✔️]FFMpeg的音频处理

149 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 30 天,点击查看活动详情

PCM

PCM全称Pulse-Code Modulation,脉冲调制编码。是未经压缩的音频采样数据裸流,由模拟信号经过采样、量化、编码转换成的标准数字音频数据。

描述PCM的6个参数:

  1. Sample Rate
    采样频率。8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
  2. Sample Size
    量化位数。通常该值为16-bit。
  3. Number of Channels
    通道个数。常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
  4. Sign
    表示样本数据是否是有符号位,比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
  5. Byte Ordering 字节序。字节序是little-endian还是big-endian。通常均为little-endian。
  6. Integer Or Floating Point 整形或浮点型。大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。

image.png

经ffmpeg解码的音频帧一般会有多个pcm采样数据(AVFrame->nb_samples),AAC_LC为1024,根据采样数据的布局和格式,我们可以算出每个帧中采样数据的内存占用

双声道AV_CH_LAYOUT_STEREO 布局,采样格式AV_SAMPLE_FMT_S16,一个AAC_LC帧采样数据占用 2*(16/8)*1024 =4096字节

对于采样率为44100Hz,一个音频帧的播放时间为 1024/44100 ≈ 23.22ms。

av_rescale_rnd

int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const;

计算 "a * b / c" 的值并分五种方式来取整 一般的使用方法

int dstNbSamples = av_rescale_rnd(
    frame->nb_samples, codecContext->sample_rate,
    codecContext->sample_rate, AV_ROUND_UP);

这个计算的是新的采样数量2:采样数量1*采样频率1/采样频率2

采样数量*采样频率=一帧的采样数量

av_samples_get_buffer_size

这个函数只能用于音频,计算要把一系列的样本保存起来,需要多大的缓存

int av_samples_get_buffer_size(
    int *linesize, // 
    int nb_channels, // 通道的数量
    int nb_samples, // 单个通道的采样数量
    enum AVSampleFormat sample_fmt, // 采样格式
    int align // 字节对齐,0默认,1不对齐
);

swr_convert

音频重新采样,解析出来的数据为pcm数据。

播放音频

ffplay也支持播放音频,但是它使用的是SDL

Windows

MciPlayer.cpp

mciSendCommand

mpg123

windows播放pcm的小例子

Android

非engine代码

  • AudioBufferProvider.h
  • AudioMixer.h
  • AudioMixerOps.h
  • AudioResampler.h
  • AudioResamplerCubic.h
  • AudioResamplerPublic.h
  • mp3reader.h
  • tinysndfile.h

播放 pcm 数据目前比较流行的有两种方式:

  • 一种是通过 Android 的 AudioTrack 来播放
  • 一种是采用跨平台的OpenSLES播放音频
  • openal: a cross-platform 3D audio API appropriate for use with gaming applications
  • sdl

SDL

SDL是 “Simple DirectMedia Layer”的缩写,SDL是一个开源的跨平台的多媒体库,封装了复杂的音视频底层操作,简化了音视频处理的难度。

Github

image.png