【秒懂音视频开发】08_音频录制 (2)

先通过命令查看一下dshow可以使用的参数,详情可以查看官方文档:。

# 从ffmpeg -devices命令的结果可以看得出来:dshow属于demuxer,而不是muxer ffmpeg -h demuxer=dshow

部分输出结果如下所示:

# 采样率 -sample_rate <int> set audio sample rate (from 0 to INT_MAX) # 采样大小(位深度) -sample_size <int> set audio sample size (from 0 to 16) # 声道数 -channels <int> set number of audio channels, such as 1 or 2 (from 0 to INT_MAX) # 列出特定设备支持的参数 -list_options <boolean> list available options for specified device (default false)

然后再看看你的设备支持哪些参数。

ffmpeg -list_options true -f dshow -i audio="麦克风阵列 (Realtek(R) Audio)"

输出结果如下所示:

DirectShow audio only device options (from audio devices) Pin "Capture" (alternative pin name "Capture") min ch=1 bits=8 rate= 11025 max ch=2 bits=16 rate= 44100 # 可以看出来:采样率范围是11025~44100Hz

接下来设置录音时的音频参数。

ffmpeg -f dshow -sample_rate 15000 -sample_size 16 -channels 1 -i audio="麦克风阵列 (Realtek(R) Audio)" out.wav 通过编程录音 主要步骤

开发录音功能的主要步骤是:

注册设备

查找输入格式

打开设备

读取数据

释放资源

以后的开发过程中,经常需要查询的资料:官方API文档。

AudioThread

录音是个耗时操作,因此最好放到一个子线程中进行。这里创建了一个继承自QThread的线程类,线程一旦启动(start),就会自动调用run函数。

AudioThread.h

#include <QThread> class AudioThread : public QThread { Q_OBJECT private: void run(); public: explicit AudioThread(QObject *parent = nullptr); ~AudioThread(); };

AudioThread.cpp

#include "audiothread.h" #include <QDebug> #include <QFile> extern "C" { // 编解码相关API #include <libavcodec/avcodec.h> // 格式相关API #include <libavformat/avformat.h> // 工具API(比如错误处理) #include <libavutil/avutil.h> } AudioThread::AudioThread(QObject *parent) : QThread(parent) { // 在线程结束时自动回收线程的内存 connect(this, &AudioThread::finished, this, &AudioThread::deleteLater); } AudioThread::~AudioThread() { // 线程销毁时,正常退出线程 quit(); requestInterruption(); wait(); } void AudioThread::run() { // 格式名称 const char *fmtName; #if defined (Q_OS_WIN) fmtName = "dshow"; #else fmtName = "avfoundation"; #endif // 根据名称找到输入格式对象 AVInputFormat *fmt = av_find_input_format(fmtName); if (fmt == NULL) { qDebug() << "找不到输入格式:" << fmtName; return; } // 设备名称 const char *deviceName; #if defined (Q_OS_WIN) deviceName = "audio=麦克风阵列 (Realtek(R) Audio)"; #else deviceName = ":0"; #endif // 格式上下文 AVFormatContext *ctx = NULL; // 选项 AVDictionary *options = NULL; // 打开输入流 int ret = avformat_open_input(&ctx, deviceName, fmt, &options); // 如果打开输入流失败 if (ret < 0) { char errbuf[1024] = {0}; av_strerror(ret, errbuf, sizeof(errbuf)); qDebug() << "打开输入流失败:" << errbuf; return; } // 定义文件 QFile file("F:/out.pcm"); // 删除旧文件 if (file.exists()) { file.remove(); } // 打开文件 if (!file.open(QIODevice::WriteOnly)){ qDebug() << "文件打开失败"; // 关闭输入流 avformat_close_input(&ctx); return; } // 数据包 AVPacket pkt; while (!isInterruptionRequested() && av_read_frame(ctx, &pkt) == 0) { // 写入数据 file.write((char *) pkt.data, pkt.size); } // 关闭文件 file.close(); // 关闭输入流 avformat_close_input(&ctx); } MainWindow

在MainWindow控制开始、结束录音。

MainWindow.h

class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_audioBtn_clicked(); private: Ui::MainWindow *ui; AudioThread *_audioThread = nullptr; };

MainWindow.cpp

#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> #include "audiothread.h" extern "C" { // 设备相关API #include <libavdevice/avdevice.h> } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 初始化libavdevice并注册所有输入和输出设备 avdevice_register_all(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_audioBtn_clicked() { // 没有线程 if (_audioThread == nullptr) { // 开启新线程 _audioThread = new AudioThread(this); _audioThread->start(); // 设置按钮文字 ui->audioBtn->setText("停止录音"); } else { // 停止录音 _audioThread->requestInterruption(); _audioThread = nullptr; // 设置按钮文字 ui->audioBtn->setText("开始录音"); } } 播放PCM ffplay -ar 44100 -ac 2 -f s16le out.pcm

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppwzp.html