1. 录音的五大步骤?
- 注册设备
- 获取输入格式对象
- 打开设备
- 采集数据
- 释放资源
2. mac 平台需要给录音项目添加权限
QMAKE_INFO_PLIST = Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSMicrophoneUsageDescription</key>
<string>record from the microphone</string>
<key>NSCameraUsageDescription</key>
<string>record from the camera</string>
</dict>
</plist>
3. 最直白的录音代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QFile>
extern "C" {
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}
#define FMT_NAME "avfoundation"
#define DEVICE_NAME ":0"
#define FILE_NAME "/Users/linsipei/Documents/ffmpeg_workspcace/out.pcm"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_startRecordAudioButton_clicked()
{
qDebug() << "on_startRecordAudioButton_clicked";
avdevice_register_all();
AVInputFormat *fmt = av_find_input_format(FMT_NAME);
if(!fmt) {
qDebug() << "找不到输入格式" << FMT_NAME;
return;
}
AVFormatContext *ctx = nullptr;
int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, nullptr);
if (ret < 0) {
char errbuf[1024] = {0};
av_strerror(ret, errbuf, sizeof (errbuf));
qDebug() << "打开设备失败" << ret;
return;
}
qDebug() << "打开设备成功" << ret;
QFile file(FILE_NAME);
if (!file.open(QFile::WriteOnly)) {
qDebug() << "文件打开失败" << FILE_NAME;
avformat_close_input(&ctx);
return;
}
qDebug() << "打开文件成功";
int count = 5000000;
AVPacket pkt;
while (count-- > 0 ) {
int reslutCode = av_read_frame(ctx,&pkt);
if ( reslutCode >= 0) {
file.write((const char*)pkt.data, pkt.size);
qDebug() << "录音成功:" << reslutCode;
} else {
continue;
}
}
file.close();
avformat_close_input(&ctx);
qDebug() << "录音结束" ;
}
4. 使用多线程技术录音
#include "audiothread.h"
#include <QDebug>
#include <QFile>
#include <QDateTime>
extern "C" {
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}
#define FMT_NAME "avfoundation"
#define DEVICE_NAME ":0"
#define FILEPATH "/Users/linsipei/Documents/ffmpeg_workspcace/out.pcm"
AudioThread::AudioThread(QObject *parent) : QThread(parent)
{
}
AudioThread::~AudioThread() {
qDebug() << "AudioThread 销毁了" ;
}
void AudioThread::setStop(bool stop) {
_stop = stop;
}
void AudioThread::run() {
qDebug() << this << "开始执行 run -----";
AVInputFormat *fmt = av_find_input_format(FMT_NAME);
if(!fmt) {
qDebug() << "找不到输入格式" << FMT_NAME;
return;
}
qDebug() << "②成功" ;
AVFormatContext *ctx = nullptr;
int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, nullptr);
if (ret < 0) {
char errbuf[1024] = {0};
av_strerror(ret, errbuf, sizeof (errbuf));
qDebug() << "打开设备失败" << ret;
return;
}
qDebug() << "③成功" ;
qDebug() << "打开设备成功" << ret;
QFile file(FILEPATH);
if (!file.open(QFile::WriteOnly)) {
qDebug() << "文件打开失败" << FILEPATH;
avformat_close_input(&ctx);
return;
}
qDebug() << "④成功" ;
qDebug() << "打开文件成功";
AVPacket pkt;
while (!_stop) {
int reslutCode = av_read_frame(ctx,&pkt);
if ( reslutCode >= 0) {
file.write((const char*)pkt.data, pkt.size);
qDebug() << "录音成功:" << reslutCode;
} else {
continue;
}
}
file.close();
avformat_close_input(&ctx);
qDebug() << "录音正常结束" ;
}