Qt+FFmpeg 实现 Windows 音频采集

作为音视频开发的初学者,本文分享基于 Qt+FFmpeg 实现 Windows 平台麦克风音频采集,并将采集到的音频数据保存为 PCM 原始文件的完整代码和解析,适合刚入门音视频开发的同学参考。

一、开发环境准备

1. 基础环境

  • 操作系统:Windows 10/11
  • Qt 版本:Qt 5.14
  • FFmpeg 版本:4.3.2

2. FFmpeg 库配置

将编译好的 FFmpeg 库(包含includelibbin目录)放在 Qt 项目的上级目录(或自定义路径),并在.pro文件中配置如下(文末附完整.pro 文件)

3.查看录音设备

ffmepg -f dshow -list_devices true -i ''

ffplay -f s16le -ar 44100 -ac 2 -i D:/out.pcm

二、核心功能说明

通过 Qt 的QThread封装音频采集逻辑,避免阻塞主线程;利用 FFmpeg 的dshow设备(Windows DirectShow)读取麦克风数据,最终将原始 PCM 数据写入文件。

三、完整代码实现

1. 项目结构

复制代码
AudioCapture/
├── audiothread.h      // 音频采集线程头文件
├── audiothread.cpp    // 音频采集线程实现
├── mainwindow.h       // 主窗口头文件
├── mainwindow.cpp     // 主窗口实现
├── main.cpp           // 程序入口
├── mainwindow.ui      // 主窗口UI(仅一个按钮)
└── AudioCapture.pro   // 项目配置文件
└── ffmpeg/            // 上级目录的FFmpeg库(include/lib/bin)

2. 项目配置文件(AudioCapture.pro

复制代码
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# 开启Qt废弃API警告
DEFINES += QT_DEPRECATED_WARNINGS

# 源文件
SOURCES += \
    audiothread.cpp \
    main.cpp \
    mainwindow.cpp

# 头文件
HEADERS += \
    audiothread.h \
    mainwindow.h

# UI文件
FORMS += \
    mainwindow.ui

# 部署规则(默认)
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

# Windows平台FFmpeg配置
win32
{
    # FFmpeg根目录(上级目录),可根据实际路径修改
    FFMPEG_HOME = ..

    # 引入FFmpeg头文件
    INCLUDEPATH += $${FFMPEG_HOME}/include

    # 链接FFmpeg库
    LIBS += -L $${FFMPEG_HOME}/lib \
            -lavdevice \
            -lavformat \
            -lavutil
            
    # 可选:自动拷贝FFmpeg的dll到输出目录(避免手动拷贝)
    # COPY_FILES += $${FFMPEG_HOME}/bin/avdevice-58.dll \
    #               $${FFMPEG_HOME}/bin/avformat-58.dll \
    #               $${FFMPEG_HOME}/bin/avutil-56.dll
}

3. 音频采集线程(AudioThread)

audiothread.
cpp 复制代码
#ifndef AUDIOTHREAD_H
#define AUDIOTHREAD_H

#include <QThread>

class AudioThread : public QThread
{
    Q_OBJECT

private:
    void run();

public:
    explicit AudioThread(QObject *parent = nullptr);
    ~AudioThread();

signals:

};

#endif // AUDIOTHREAD_H
audiothread.cpp
cpp 复制代码
#include "audiothread.h"

#include "qdebug.h"
#include <qfile.h>

// 引入FFmpeg的C接口(extern "C"避免C++名称修饰问题)
extern "C"
{
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}

// Windows平台配置(按需修改设备名称和输出路径)
#ifdef Q_OS_WIN
    // dshow设备格式
    #define FMT_NAME "dshow"
    // 麦克风设备名(需替换为自己的设备名)
    #define DEVICE_NAME "audio=麦克风阵列 (英特尔® 智音技术)"
    // PCM输出文件路径
    #define FILENAME "D:/out.pcm"
#endif

AudioThread::AudioThread(QObject *parent) : QThread(parent)
{
    // 线程结束后自动回收内存
    connect(this,&AudioThread::finished,this,&AudioThread::deleteLater);
}

AudioThread::~AudioThread()
{
    // 安全终止线程
    requestInterruption();
    quit();
    wait();

    qDebug() << this << "音频线程析构完成";
}

void AudioThread::run()
{
    // 1. 获取DShow输入格式对象
    AVInputFormat* fmt = av_find_input_format(FMT_NAME);
    if(!fmt)
    {
        qDebug() << "获取输入格式对象失败:" << FMT_NAME;
        return;
    }

    // 2. 创建并打开音频设备上下文
    AVFormatContext* ctx = nullptr;
    int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, nullptr);
    if(ret < 0)
    {
        char errbuf[1024];
        av_strerror(ret, errbuf, sizeof(errbuf));
        qDebug() << "打开设备失败:" << errbuf;
        return;
    }

    // 3. 打开PCM文件用于写入
    QFile file(FILENAME);
    if(!file.open(QIODevice::WriteOnly))
    {
        qDebug() << "文件打开失败:" << FILENAME;
        avformat_close_input(&ctx); // 释放设备资源
        return;
    }

    // 4. 循环采集音频数据(★初学易踩坑:条件需为!isInterruptionRequested())
    AVPacket pkt;
    while(!isInterruptionRequested() && av_read_frame(ctx, &pkt) == 0)
    {
        // 将采集到的音频数据写入文件
        file.write((const char*)pkt.data, pkt.size);
        // 释放数据包引用(避免内存泄漏)
        av_packet_unref(&pkt);
    }

    // 5. 释放所有资源
    file.close();                  // 关闭文件
    avformat_close_input(&ctx);    // 关闭音频设备
    qDebug() << "音频采集结束,PCM文件已保存至:" << FILENAME;
}

4. 主窗口(MainWindow)

mainwindow.h
cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "audiothread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_audioBtn_clicked();

private:
    Ui::MainWindow *ui;
    AudioThread *_audioThread;
};
#endif // MAINWINDOW_H
mainwindow.cpp
cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qdebug.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    _audioThread = nullptr; // 初始化线程指针
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 录音按钮点击事件处理
void MainWindow::on_audioBtn_clicked()
{
    if(!_audioThread)       // 未开始采集:启动线程
    {
        _audioThread = new AudioThread(this);
        _audioThread->start();
        ui->audioBtn->setText("结束录音");
        qDebug() << "开始音频采集...";
    }
    else                    // 已开始采集:终止线程
    {
        _audioThread->requestInterruption();
        _audioThread = nullptr;
        ui->audioBtn->setText("开始录音");
        qDebug() << "停止音频采集...";
    }
}

5. 程序入口(main.cpp)

cpp 复制代码
#include "mainwindow.h"

#include <QApplication>

// 引入FFmpeg设备注册接口
extern "C"{
#include <libavdevice/avdevice.h>
}

int main(int argc, char *argv[])
{
   // 注册FFmpeg所有输入输出设备(必须!否则无法找到dshow设备)
    avdevice_register_all();

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

四、核心代码解析

1. FFmpeg 核心流程

步骤 核心函数 作用
注册设备 avdevice_register_all() 注册 FFmpeg 所有设备,是使用 dshow 的前提
获取输入格式 av_find_input_format("dshow") 拿到 Windows DirectShow 输入格式对象
打开设备 avformat_open_input() 打开指定麦克风设备,返回设备上下文
采集数据 av_read_frame() 循环读取音频数据包(AVPacket)
释放资源 avformat_close_input()/av_packet_unref() 关闭设备、释放数据包,避免内存泄漏

五、运行说明

  1. 配置 FFmpeg 路径 :将编译好的 FFmpeg 库(include/lib/bin)放在项目上级目录,或修改.pro文件中的FFMPEG_HOME路径;

  2. 修改设备名称 :通过上述 FFmpeg 命令查看并替换DEVICE_NAME

  3. 编译运行

    • 点击 "开始录音",麦克风开始采集音频;
    • 点击 "结束录音",停止采集并生成D:/out.pcm文件;
  4. 验证 PCM 文件 :PCM 是原始音频数据,无头部信息,需用 FFmpeg 转为 WAV 播放:

    复制代码
    ffmpeg -f s16le -ar 44100 -ac 2 -i D:/out.pcm output.wav

    (参数说明:s16le=16 位深度、ar 44100=44.1kHz 采样率、ac 2= 双声道,需匹配实际采集参数)

六、注意事项

  1. 编译器匹配:确保 FFmpeg 库的编译环境(MSVC/Mingw)与 Qt 编译器一致,否则会链接失败;
  2. 权限问题:Windows 需授予程序麦克风访问权限;
  3. DLL 拷贝 :运行程序时需将 FFmpeg 的avdevice-58.dllavformat-58.dllavutil-56.dll拷贝到程序输出目录(或开启.pro 文件中的COPY_FILES自动拷贝);
  4. 线程安全 :Qt 线程通过requestInterruption()终止,避免直接调用terminate()(不安全)。

总结

本文实现了最基础的 Windows 音频采集功能,核心是理解 FFmpeg 的设备操作流程和 Qt 线程的安全使用。初学者可先掌握核心流程,再逐步学习音频编码、封装等进阶知识,为后续音视频开发打下基础。

相关推荐
njsgcs2 小时前
ModelScope下载模型+ vLLM调用+内存释放
windows·wsl·vllm
草莓熊Lotso2 小时前
Qt 控件美化与交互进阶:透明度、光标、字体与 QSS 实战
android·java·开发语言·c++·人工智能·git·qt
黄美美分享3 小时前
Windows自动化设置工具,无需编程让电脑自动工作!定时任务软件!打工人必备软件
运维·windows·自动化·电脑
ssxueyi3 小时前
Git 完整安装与环境配置教程(Windows/macOS/Linux 通用)
windows·git·macos·项目管理·git教程·代码管理
上天夭4 小时前
补充提问(四)
windows·python
南知意-4 小时前
仅 10MB 开源工具,一键远程唤醒关机电脑!
windows·开源·电脑·工具·远程开机
呉師傅5 小时前
东芝复印机简单使用说明(2010AC等黑壳机)
运维·服务器·windows·电脑·wps
A懿轩A5 小时前
【2026 最新】Kuikly 编译开发 OpenHarmony 项目逐步详细教程带图操作Android Studio编译(Windows)
windows·harmonyos·鸿蒙·openharmony·kuikly
GGGLF5 小时前
Qt网络/串口通信开发:QByteArray 数据类型转换方法解析
开发语言·qt