Ubuntu下使用Qt和ffmpeg,打开音频采集设备并读取数据
- 引入编译好的ffmpeg库文件和头文件。
(1)在.pro文件中加入:
unix:!macx: LIBS += -L$$PWD/../../../usr/local/ffmpeg/lib/
-lavcodec -lavdevice -lavfilter -lavformat -lavutil -lswresample -lswscale
INCLUDEPATH += $$PWD/../../../usr/local/ffmpeg/include
DEPENDPATH += $$PWD/../../../usr/local/ffmpeg/include
即可引入库文件,库文件路径根据自己的编译路径修改,我的路径是/usr/local/ffmpeg。
(2)也可通过在Qt Creator中引入外部库文件的方式引入ffmpeg。
2.引入所需头文件
extern "C"
{
#include "libavdevice/avdevice.h"
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
}
注意:ffmpeg是C语言编写的,C++环境下需要加上extern “C”,否则程序编译会报错。
- 打开设备
void MainWindow::openDevice()
{
// 注册设备
avdevice_register_all();
// 获取采集格式
AVInputFormat *inputFmt = av_find_input_format("alsa");
int ret = 0;
AVFormatContext *fmt_ctx = nullptr;
char *deviceName = "hw:0,0";
AVDictionary *options = nullptr;
// 打开设备
ret = avformat_open_input(&fmt_ctx, deviceName, inputFmt, &options);
char errors[1024];
if (ret < 0)
{
av_strerror(ret, errors, 1024);
printf("Failed to open audio device, [%d]%s\n", ret, errors);
}
}
- 从设备读取音频数据
- 增加头文件
#include "libavcodec/avcodec.h"
读取代码:
void MainWindow::openDeviceAndReadData()
{
// 设置日志级别
av_log_set_level(AV_LOG_DEBUG);
// 注册设备
avdevice_register_all();
// 获取采集格式
AVInputFormat *inputFmt = av_find_input_format("alsa");
int ret = 0;
AVFormatContext *fmt_ctx = nullptr;
char *deviceName = "hw:0,0";
AVDictionary *options = nullptr;
// 打开设备
ret = avformat_open_input(&fmt_ctx, deviceName, inputFmt, &options);
char errors[1024] = {0};
if (ret < 0)
{
av_strerror(ret, errors, 1024);
printf("Failed to open audio device, [%d]%s\n", ret, errors);
return;
}
int count = 0;
AVPacket packet;
av_init_packet(&packet);
// 从设备读取数据
while ((ret = av_read_frame(fmt_ctx, &packet) == 0) && count++ < 500)
{
av_log(NULL, AV_LOG_INFO, "Packet size: %d(%p), count = %d\n",
packet.size, packet.data, count);
// 释放packet空间
av_packet_unref(&packet);
}
// 关闭设备,释放上下文空间
avformat_close_input(&fmt_ctx);
av_log(NULL, AV_LOG_DEBUG, "Finish!\n");
}
使用完上下文AVFormatContext 和AVPacket以后要注意释放空间,避免内存泄漏。
注:1. C语言和C++中手动分配的空间使用完以后要记得释放,避免内存泄漏,否则服务端程序不断申请内存空间而不释放,最终会导致程序崩溃。
2. 指针变量释放以后,要置为NULL,避免野指针。在多线程中,如果在线程1中的指针释放了其指向的内存地址,没有置为NULL,之后这块空间被线程2使用,而此时线程1中的指针依然可以访问并修改这块内存空间,如果线程1中的指针修改了内存内容,则会对线程2造成影响,产生不可估计的后果。