type
status
date
slug
summary
tags
category
icon
password
Property
Mar 25, 2023 06:21 AM

基础知识

重采样简介

  • 什么是重采样?
    • 所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。
  • 为什么要重采样?
    • 当然是原有的⾳频参数不满⾜我们的需求,⽐如在FFmpeg解码⾳频的时候,不同的⾳源有不同的格式,采样率等,在解码后的数据中的这些参数也会不⼀致(最新FFmpeg 解码⾳频后,⾳频格 式为AV_SAMPLE_FMT_FLTP,这个参数应该是⼀致的),如果我们接下来需要使⽤解码后的⾳频数据做其他操作,⽽这些参数的不⼀致导致会有很多额外⼯作,此时直接对其进⾏重采样,获取我们制定的⾳频参数,这样就会⽅便很多。再⽐如在将⾳频进⾏SDL播放时候,因为当前的SDL2.0不⽀持planar格式,也不⽀持浮点型的,因此就需要我们对其重采样,使之可以在SDL2.0上进⾏播放。
      notion image
  • 可调节的参数:
      1. sample rate(采样率)
      1. sample format(采样格式)
      1. channel layout(通道布局),可以通过此参数获取声道数

对应参数解析

  • 采样率:采样设备每秒抽取样本的次数
  • 采样格式及量化精度(位宽):每种⾳频格式有不同的量化精度(位宽),位数越多,表示值就越精确,声⾳表现⾃然就越精准。 FFmpeg中⾳频格式有以下⼏种,每种格式有其占⽤的字节数信息(libavutil/samplefmt.h):
    • notion image
      notion image
  • 分片(plane)和打包(packed):以双声道为例,带P(plane)的数据格式在存储时,其左声道和右声道的数据是分开存储的,左声道的数据存储在data[0],右声道的数据存储在data[1],每个声道的所占⽤的字节数为linesize[0]和linesize[1];不带P(packed)的⾳频数据在存储时,是按照LRLRLR...的格式交替存储在data[0]中,linesize[0]表示总的数据量。
  • 声道分布(channel_layout):声道分布在FFmpeg\libavutil\channel_layout.h中有定义,⼀般来说⽤的⽐较多的是AV_CH_LAYOUT_STEREO(双声道)和AV_CH_LAYOUT_SURROUND(三声道),这两者的定义如下:
    • #define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) #define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)
    • 在 FFmpeg 中,SampleFormat(采样格式)和 ChannelLayout(通道布局)是两个重要的概念,用于描述音频数据的格式和布局。它们的区别如下:
        1. SampleFormat(采样格式):表示音频采样的编码格式,包括采样精度和采样方式两个方面。采样精度通常是指一个样本占用的位数,例如8位、16位、24位等,而采样方式则是指采样值的表示方式,包括有符号整数、无符号整数、浮点数等。常见的采样格式包括 S16、S32、FLTP、ALAW、ULAW 等。
        1. ChannelLayout(通道布局):表示音频数据的通道数和布局方式。通道数指音频数据中的通道数量,例如单声道、立体声、5.1声道等,而通道布局则是指这些通道在数据中的排列方式,例如前左、前右、中央、后左、后右等。常见的通道布局包括 mono、stereo、2.1、5.1、7.1 等。
        在 FFmpeg 中,采样格式和通道布局通常会同时出现,用于描述音频数据的完整格式。例如,S16P 表示每个采样点占用 16 位,采样值以有符号整数方式存储,同时包含多个声道,声道布局根据 FFmpeg 中定义的枚举值进行描述。
        在音视频处理中,正确理解采样格式和通道布局对于保证音视频数据的正确处理和解码非常重要。如果采样格式或通道布局不正确,可能会导致音视频解码出现噪声、失真等问题。因此,在进行音视频处理时,需要根据实际情况正确设置采样格式和通道布局,以获得更好的音视频效果
  • ⾳频帧的数据量计算
    • ⼀帧⾳频的数据量(字节)= channel数 * nb_samples样本数 * 每个样本占⽤的字节数
    • 如果该⾳频帧是FLTP格式的PCM数据,包含1024个样本,双声道,那么该⾳频帧包含的⾳频数据量是 2 * 1024 * 4 = 8192字节 AV_SAMPLE_FMT_DBL :2 * 1024 * 8 = 16384字节
  • 音频播放时间计算
    • 以采样率44100Hz来计算,每秒44100个sample,而正常⼀帧为1024个sample,可知每帧播放时间/1024=1000ms/44100,得到每帧播放时间=1024*1000/44100=23.2ms (更精确的是 23.21995464852608)。
    • ⼀帧播放时间(毫秒) = nb_samples样本数 * 1000 / 采样率 = (1)1024 * 1000 / 44100 = 23.21995464852608ms ->约等于 23.2ms,精度损失了 0.011995464852608ms,如果累计10万帧,误差>1199毫秒,如果有视频⼀起的就会有音视频同步的问题。 如果按着23.2去计算pts(0 23.2 46.4 )就会有累积误差。 (2)1024 * 1000 / 48000 = 21.33333333333333ms

FFmpeg重采样API

  • swr_alloc() :用于创建一个 SwrContext 上下文结构体,用于保存重采样过程中的参数和状态信息。
    • SwrContext 上下文结构体是 libswresample 库中最基本的数据结构,它包含了进行音频重采样所需要的所有参数和状态信息,包括输入采样率、输出采样率、输入采样格式、输出采样格式、输入通道布局、输出通道布局等。
    • 使用 swr_alloc() 函数可以创建一个 SwrContext 上下文结构体,并返回该结构体的指针。SwrContext 上下文结构体需要使用 swr_free() 函数进释放。
    • 以下是 swr_alloc() 函数的定义:
  • swr_alloc_set_opts() :用于创建一个 SwrContext 上下文结构体,并设置输入和输出音频参数。
    • 以下是 swr_alloc_set_opts() 函数的定义:
    • s 参数是一个可选的 SwrContext 上下文结构体指针,可以为 NULL,如果不为 NULL,则会将输入和输出音频参数设置到 s 上下文结构体中。如果 s 为 NULL,则会自动创建一个 SwrContext 上下文结构体,并将输入和输出音频参数设置到该结构体中,并返回结构体指针。
    • out_ch_layout、out_sample_fmt、out_sample_rate 分别表示输出音频的通道布局、采样格式和采样率;
    • in_ch_layout、in_sample_fmt、in_sample_rate 分别表示输入音频的通道布局、采样格式和采样率。
    • log_offset 和 log_ctx 参数用于设置日志输出的偏移量和上下文信息。
    • 与 swr_alloc() 函数不同的是:swr_alloc_set_opts() 函数可以在创建 SwrContext 上下文结构体时,一次性设置输入和输出音频的采样率、采样格式、通道布局等参数,并自动选择合适的重采样算法和重采样选项。这样,可以方便地将音频从一种格式转换为另一种格式。
      notion image
      notion image
    • av_opt_set_channel_layout() :是 FFmpeg 中的 libavutil 库提供的一个函数,用于设置音频编解码器上下文中的通道布局。
      • 通道布局是描述音频数据各个声道之间位置关系的一组参数。不同的通道布局方式可以描述不同的声道排列方式,如立体声、5.1 声道、7.1 声道等。
        av_opt_set_channel_layout() 函数的函数原型如下:
      • obj 参数是需要设置通道布局的音频编解码器上下文结构体的指针;
      • name 参数是指定通道布局属性的名称字符串,一般为 "channel_layout";
      • ch_layout 参数是需要设置的通道布局,是一个 64 位的整数,可以通过 AV_CH_LAYOUT_* 宏定义来指定,例如 AV_CH_LAYOUT_STEREO、AV_CH_LAYOUT_5POINT1 等;
      • log_offset 参数是日志输出偏移量,一般设置为 0。
    • av_opt_set_int() :是 FFmpeg 中的 libavutil 库提供的一个函数,用于设置音视频编解码器上下文中的整数类型参数。
      • av_opt_set_int() 函数的函数原型如下:
      • obj 参数是需要设置参数的音视频编解码器上下文结构体的指针;
      • name 参数是参数名称的字符串,例如 "bit_rate"、"width"、"height" 等;
      • value 参数是需要设置的参数值;
      • search_flags 参数是搜索标志,一般设置为 0。
    • av_opt_set_sample_fmt() :是 FFmpeg 中的 libavutil 库提供的一个函数,用于设置音频编解码器上下文中的采样格式参数。
      • 采样格式是描述音频数据的样本格式,例如 s16、s32、flt 等。不同的采样格式对应不同的位深、精度和动态范围。
        av_opt_set_sample_fmt() 函数的函数原型如下:
      • obj 参数是需要设置参数的音频编解码器上下文结构体的指针;
      • name 参数是参数名称的字符串,例如 "sample_fmt";
      • fmt 参数是需要设置的采样格式,是一个 AVSampleFormat 枚举类型的值,例如 AV_SAMPLE_FMT_S16、AV_SAMPLE_FMT_S32、AV_SAMPLE_FMT_FLT 等;
      • search_flags 参数是搜索标志,一般设置为 0。
  • swr_init():用于初始化 SwrContext 上下文结构体,以便开始进行音频重采样。
    • 在创建 SwrContext 上下文结构体并设置好输入和输出采样格式、通道布局等参数后,需要调用 swr_init() 函数来初始化上下文结构体,以便开始进行音频重采样。swr_init() 函数会根据输入和输出采样格式、通道布局等参数,自动选择合适的重采样算法,并计算出重采样所需的内部参数和状态信息。
    • 以下是 swr_init() 函数的定义:
    • s 参数是 SwrContext 上下文结构体的指针。swr_init() 函数会返回一个整数值,表示初始化是否成功。如果返回值小于 0,则表示初始化失败,需要检查输入和输出采样格式、通道布局等参数是否设置正确。
  • swr_convert():用于将输入音频数据重采样为输出音频数据。
    • 在使用 SwrContext 上下文结构体设置好输入和输出采样格式、通道布局等参数,并通过 swr_init() 函数初始化上下文结构体后,可以使用 swr_convert() 函数将输入音频数据重采样为输出音频数据。swr_convert() 函数会将输入音频数据按照输入采样格式、通道布局等参数进行重采样,并将重采样后的音频数据存储到输出缓冲区中,同时返回重采样后的音频数据的采样数量。
    • 以下是 swr_convert() 函数的定义:
    • s 参数是 SwrContext 上下文结构体的指针;
    • out 参数是指向输出音频数据缓冲区的指针,缓冲区的大小需要预先分配,大小应为 out_count *av_get_bytes_per_sample(out_sample_fmt);
    • out_count 参数表示输出音频数据的采样数量;
    • in 参数是指向输入音频数据缓冲区的指针;
    • in_count 参数表示输入音频数据的采样数量。
      • 在特定情况下,可以将 in 和 in_count 参数设置为 NULL 和 0,用于清空重采样上下文的缓冲区,例如在切换音频流时,需要清空重采样上下文的缓冲区,防止上一段音频的残留数据影响下一段音频的重采样。
      返回值 <= out_count
      在调用 swr_convert() 函数时,需要保证输入和输出采样格式、通道布局等参数与 SwrContext 上下文结构体中设置的参数一致,否则会导致重采样失败。
      notion image
  • swr_free() :用于释放 SwrContext 上下文结构体占用的内存空间。
    • 在使用 SwrContext 上下文结构体完成音频重采样操作后,需要使用 swr_free() 函数释放上下文结构体占用的内存空间,避免内存泄漏。
      以下是 swr_free() 函数的定义:
    • s 参数是 SwrContext 上下文结构体的指针的指针。在调用 swr_free() 函数时,需要将 SwrContext 上下文结构体的指针的指针作为参数传递给该函数,以便在函数中将其占用的内存空间释放。
MSYS2 编译 FFmpeg 库FFmpeg 自定义 IO 操作之 AVIO 解析