项目前准备,我的FFmpeg整个目录是放在和项目文件夹同级
1、在QT项目中集成FFmpeg。
主要是在.pro项目文件中把FFmpeg的include路径和lib库的路径添加就可以了。代码如下:
win32 {
FFMPEG_HOME = ../ffmpeg-4.2.1-win32-dev
}
INCLUDEPATH += $${FFMPEG_HOME}/include
LIBS += -L$${FFMPEG_HOME}/lib \
-lavdevice \
-lavformat \
-lavutil
2、在MainWindow中拖入一个按钮,并转为槽
(其实就是相当于其他开发的监听按钮的点击事件)
//录音按钮
/*
* 命令行录音:ffmpeg -f dshow -i audio="设备名" out.wav
* 修改录音参数:ffmpeg -f dshow -sample_rate 15000 -sample_size 16 -channels 2 -i audio="设备名" out.wav
*/
/*
代码录音的逻辑
1、注册设备
2、获取输入格式对象
3、打开设备
4、采集数据
5、释放资源
*/
void MainWindow::on_recorButton_clicked()
{
//点击了 开始录音
if(!_recordThread){
//创建并启动线程
_recordThread = new RecordThread(this);
_recordThread->start();
//监听线程异常退出的情况
connect(_recordThread,&RecordThread::finished,
[this](){
_recordThread = nullptr;
//修改按钮文字
ui->recorButton->setText("开始录音");
});
//修改按钮文字
ui->recorButton->setText("停止录音");
}else{
//主动请求提前完成
_recordThread->requestInterruption();
_recordThread = nullptr;
//修改按钮文字
ui->recorButton->setText("开始录音");
}
}
3、因为录音是不断地读取数据,耗时操作,所以开了一个子线程在线程的run函数中去录音
#include "recordthread.h"
#include <QDebug>
#include <QFile>
#include <QDateTime>
extern "C" {
//设备相关API
#include <libavdevice/avdevice.h>
//格式相关API
#include <libavformat/avformat.h>
//工具相关API
#include <libavutil/avutil.h>
}
//宏定义
//输入格式名
#define FMT_NAME "dshow"
//设备名
#define DEVICE_NAME "audio=麦克风阵列 (适用于数字麦克风的英特尔® 智音技术)"
//
#define FILE_PATH "C:/Users/love/Desktop/QTWork/09_recordAudio_sdl_playPCM/"
//构造函数
RecordThread::RecordThread(QObject *parent) : QThread(parent)
{
//监听线程执行完成后调用函数回收内存
connect(this, &RecordThread::finished, this, &RecordThread::deleteLater);
}
//析构函数
RecordThread::~RecordThread(){
//断开所有监听
disconnect();
//主动请求提前完成
requestInterruption();
quit();
wait();
qDebug() << this << "录音线程析构函数------";
}
/*
* 命令行录音:ffmpeg -f dshow -i audio="设备名" out.wav
* 修改录音参数:ffmpeg -f dshow -sample_rate 15000 -sample_size 16 -channels 2 -i audio="设备名" out.wav
*/
/*
代码录音的逻辑
1、注册设备
2、获取输入格式对象
3、打开设备
4、采集数据
5、释放资源
*/
//线程启动会自动调用内部的run函数
void RecordThread::run(){
qDebug() << this << "录音线程开始";
//1、注册设备 (只需要注册一次 所以在main函数里注册就好了)
//2、获取输入格式对象
AVInputFormat *fmt = av_find_input_format(FMT_NAME);
if(!fmt){
qDebug() << this << "av_find_input_format error" << fmt;
}
//3、打开设备
//上下文 操作设备
AVFormatContext *ctx = nullptr;
//url 设备名
//const char* deviceName = "";
//选项
//AVDictionary *options;
int ret = avformat_open_input(&ctx,DEVICE_NAME, fmt, nullptr);
if(ret){//0 表示成功。 非0即真
char errbuff[1024];
av_strerror(ret,errbuff,sizeof(errbuff));
qDebug() << this << "avformat_open_input error" << errbuff;
return;
}
//4、采集数据
//拼接文件名
QString fileName = FILE_PATH;
fileName += QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
fileName += ".pcm";
QFile file(fileName);
//打开文件 WriteOnly这个模式打开文件,如果文件不存在就创建文件并打开,如果文件存在就清空
bool fopen = file.open(QIODevice::WriteOnly);
if(!fopen){
//打开文件失败 需要关闭设备 否则内存泄漏
avformat_close_input(&ctx);
qDebug() << this << "file.open error" << fileName;
return;
}
//数据包
AVPacket pkt;
//不断地读取数据
while (!isInterruptionRequested()) {
ret = av_read_frame(ctx,&pkt);
if(ret == 0){
//读取成功 把数据写入文件
file.write((char *)pkt.data,pkt.size);
}else{
//关闭文件
file.close();
//关闭设备
avformat_close_input(&ctx);
break;
}
}
//5、释放资源
//关闭文件
file.close();
//关闭设备
avformat_close_input(&ctx);
qDebug() << this << "录音线程正常退出";
}