音频采集 via FFmpeg

FFmpeg 简介

FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用 LGPL 或 GPL 许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频 / 视频编解码库 libavcodec,为了保证高可移植性和编解码质量,libavcodec 里很多 code 都是从头开发的。

FFmpeg 在 Linux 平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括 Windows、Mac OS X 等。这个项目最早由 Fabrice Bellard 发起,2004 年至 2015 年间由 Michael Niedermayer 主要负责维护。许多 FFmpeg 的开发人员都来自 MPlayer 项目,而且当前 FFmpeg 也是放在 MPlayer 项目组的服务器上。项目的名称来自 MPEG 视频编码标准,前面的 “FF” 代表 “Fast Forward”。

FFmpeg 命令行采集音频

FFmpeg 提供了现成的程序用命令行的方式对音频进行采集。

  • 首先需要枚举电脑上的音频采集设备:
>ffmpeg.exe -list_devices true -f dshow -i dummy
… …
[dshow @ 007bd020] DirectShow video devices (some may be both video and audio devices)
[dshow @ 007bd020]  “USB Web Camera - HD"
[dshow @ 007bd020]     Alternative name "@device_pnp_\\?\usb#vid_1bcf&pid_288e&mi_00#7&6c75a67&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
[dshow @ 003cd000] DirectShow audio devices
[dshow @ 003cd000]  "Microphone (Realtek High Defini"
[dshow @ 003cd000]     Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\Microphone (Realtek High Defini“

在我的电脑上有两个采集设备,一个是用来采集视频的摄像头,一个是用来采集音频的麦克风“Microphone (Realtek High Defini ”(此处名称因为太长被截断)。

  • 然后选择麦克风设备进行采集
>ffmpeg.exe -f dshow -i audio="Microphone (Realtek High Defini" d:\test.mp3 
... ...
Guessed Channel Layout for Input Stream #0.0 : stereo
Input #0, dshow, from 'audio=Microphone (Realtek High Defini':
  Duration: N/A, start: 38604.081000, bitrate: 1411 kb/s
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (pcm_s16le (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'd:\test.mp3':
  Metadata:
    TSSE            : Lavf57.71.100
    Stream #0:0: Audio: mp3 (libmp3lame), 44100 Hz, stereo, s16p
    Metadata:
      encoder       : Lavc57.89.100 libmp3lame
size=102kB time=00:00:06.48 bitrate=128.7kbits/s speed=2.13x ← 正在录制的音频信息,会实时变化

FFmpeg 在 Windows 上用的是 DirectShow 输入设备进行采集的,然后经由自己的 mp3 encoder 和 file writer 写到磁盘上。

FFmpeg API 采集音频

FFmpeg 还提供了完备的 API 对音频进行采集。

下面是使用 FFmpeg 采集并编码音频的流程图。使用该流程,可以编码 MP3、AAC、FLAC 等等各种 FFmpeg 支持的音频。
FFmpeg 采集音频

音频重采样

音频重采样 是转换已采样的音频数据的过程,比如当输入输出数据的采样率不一致时,或者声道数不一致时,就需要重采样。音频重采样主要步骤是进行抽取或插值。由于抽取可能产生混叠,插值可能产生镜像,因此需要在抽取前进行抗混叠滤波,在插值后进行抗镜像滤波。抗混叠滤波和抗镜像滤波都是使用低通滤波器实现。

FFmpeg 提供了重采样的 API,主要流程如下:

swr_alloc_set_opts
swr_init
swr_convert
swr_free

采集音频代码

以下是整个 FFmpeg 采集过程的概要代码,略去各个函数的具体实现和资源释放。

本文中的代码基于 FFmpeg 4.1。

hr = open_cap_device(AVMEDIA_TYPE_AUDIO, &cap_fmt_ctx, &cap_codec_ctx);
GOTO_IF_FAILED(hr);

hr = open_output_audio_file(out_file, cap_codec_ctx, &out_fmt_ctx, &enc_ctx);
GOTO_IF_FAILED(hr);

hr = init_resampler(cap_codec_ctx, enc_ctx, &resample_ctx);
GOTO_IF_FAILED(hr);

hr = init_fifo(&fifo, enc_ctx);
GOTO_IF_FAILED(hr);

hr = avformat_write_header(out_fmt_ctx, NULL);
GOTO_IF_FAILED(hr);

while (_kbhit() == 0) {
   
    // Infinitely capture audio until a key input.
    int finished = 0;
    hr = audio_transcode( cap_fmt_ctx, cap_codec_ctx, out_fmt_ctx, enc_ctx,
            	      fifo, resample_ctx, 0, &finished, false, true );
    GOTO_IF_FAILED(hr);
    if (finished)
        break;
}

flush_encoder(out_fmt_ctx, enc_ctx);

hr = av_write_trailer(out_fmt_ctx);
GOTO_IF_FAILED(hr);

open_cap_device 函数

在 Windows 上 FFmpeg 使用 DirectShow 的设备进行采集,这里我们先枚举所有的设备,然后选用第一个成功初始化的设备。

int open_cap_device(
    AVMediaType cap_type,
    AVFormatContext **cap_fmt_ctx, 
    AVCodecContext **cap_codec_ctx,
    AVDictionary** options = NULL)
{
   
   
    RETURN_IF_NULL(cap_fmt_ctx);
    RETURN_IF_NULL(cap_codec_ctx);
    *cap_fmt_ctx = NULL;
    *cap_codec_ctx = NULL;
    int hr = -1;
    std::string cap_device_name;
    std::vector<std::wstring> cap_devices;

    avdevice_register_all();
    CoInitialize(NULL);

    AVInputFormat* input_fmt = av_find_input_format("dshow");
    GOTO_IF_NULL(input_fmt);

    switch (cap_type) {
   
   
    case AVMEDIA_TYPE_AUDIO:
        cap_device_name = "audio=";
        hr = enum_dshow_acap_devices(cap_devices);
        break;
    }
    GOTO_IF_FAILED(hr);

    cap_device_name += unicodeToUtf8(cap_devices[0].c_str());
    hr = avformat_open_input(cap_fmt_ctx, cap_device_name.c_str(), input_fmt, options);
    GOTO_IF_FAILED(hr);

    hr = avformat_find_stream_info(*cap_fmt_ctx, NULL);
    GOTO_IF_FAILED(hr);

    for (unsigned int i = 0; i < (*cap_fmt_ctx)->nb_streams; i++) {
   
   
        AVCodecParameters* codec_par = (*cap_fmt_ctx)->streams[i]->codecpar;
        if (codec_par->codec_type == cap_type) {
   
   
            av_dump_format(*cap_fmt_ctx, i, NULL, 0);

            AVCodec* decoder = avcodec_find_decoder(codec_par->codec_id);
            GOTO_IF_NULL(decoder);

            *cap_codec_ctx = avcodec_alloc_context3(decoder)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值