前记:
上一篇记录了第一次使用Qt调WebRTC的库,但仅仅输出了梧桐摄像头的名字,本次展示一个简单的示例,展示如何从本地摄像头获取数据,并显示在Qt的界面上
一、编写源码
1.编辑工程文件(*.pro)
在qtcreator中,新建一下VS2019的工程,打开工程文件,添加如下代码
(1)添加webRTC静态库
#请将{webrtcdir}替换为自己的实际目录
win32:CONFIG(release, debug|release): LIBS += -L{webrtcdir}/src/out/Release_qt/obj/ -lwebrtc
else:win32:CONFIG(debug, debug|release): LIBS += -L{webrtcdir}/src/out/Default_qt/obj/ -lwebrtc
INCLUDEPATH += {webrtcdir}/src
DEPENDPATH += {webrtcdir}/src
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += {webrtcdir}/src/out/Release_qt/obj/libwebrtc.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += {webrtcdir}/src/out/Default_qt/obj/libwebrtc.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += {webrtcdir}/src/out/Release_qt/obj/webrtc.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += {webrtcdir}/src/out/Default_qt/obj/webrtc.lib
(2)修改VS运行时
QMAKE_CXXFLAGS_RELEASE += /MT
QMAKE_CFLAGS_RELEASE += /MT
QMAKE_CXXFLAGS_DEBUG += /MTd
QMAKE_CFLAGS_DEBUG += /MTd
(3)添加需要链接的静态库
LIBS += -lstrmiids -lOle32 -lOleAut32 -lwinmm -luser32
(4)添加第三方库
#请将{webrtcdir}替换为自己的实际目录
INCLUDEPATH += {webrtcdir}/src/third_party/abseil-cpp
DEPENDPATH += {webrtcdir}/src/third_party/abseil-cpp
INCLUDEPATH += {webrtcdir}/src/third_party/libyuv/include
DEPENDPATH += {webrtcdir}/src/third_party/libyuv/include
(5)增加宏定义
DEFINES += WEBRTC_WIN
2.编写处理数据帧的类CaptureObserver
(1)头文件
关键代码:
增加头文件的引用
#include "modules/video_capture/video_capture_factory.h"
#include "rtc_base/synchronization/mutex.h"
#include "third_party/libyuv/include/libyuv/convert_argb.h"
类CaptureObserver是从VideoSinkInterface公有继承的
class CaptureObserver : public rtc::VideoSinkInterface<webrtc::VideoFrame>
重载帧处理的函数
//处理接收到的帧
void OnFrame(const webrtc::VideoFrame& videoFrame) override;
(2)源文件
关键代码:
重新实现帧处理的函数
webrtc::MutexLock lock(&capture_lock_);
int height = videoFrame.height();
int width = videoFrame.width();
incoming_frames_++;
qDebug()<<"width"<<width<<"height"<<height<<"incoming_frames_"<<incoming_frames_;
//将收到的数据帧转换下格式
rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
videoFrame.video_frame_buffer()->ToI420());
//开辟一段存放BGR数据的空间
const int length =buffer->width()* buffer->height()*3;
qDebug()<<"buffer->width()"<<buffer->width()<<"buffer->height()"<<buffer->height();
uchar *imageBuffer=new uchar[length];
//使用libyuvy库转换一帧数据到BGR
libyuv::I420ToRGB24(buffer->DataY(), buffer->StrideY(), buffer->DataU(),
buffer->StrideU(), buffer->DataV(), buffer->StrideV(),
imageBuffer,
buffer->width()*3,
buffer->width(), buffer->height());
//将得到的数据放入QImage中
QImage image(imageBuffer,buffer->width(), buffer->height(), QImage::Format_BGR888);
qDebug()<<image;
m_lastImage=image.copy();
delete imageBuffer;
2.修改类MainWindow
(1)修改UI
如下图所示,设计器中加入以下窗口部件
(2)修改头文件
//增加需要的引用
#include "modules/video_capture/video_capture.h"
#include "modules/video_capture/video_capture_factory.h"
#include "captureobserver.h"
#include <QMainWindow>
#include <QDebug>
#include <QTimer>
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_pushButton_clicked();
private:
//初始化界面上的设备列表
void getDeviceList();
Ui::MainWindow *ui;
QTimer m_timer;
rtc::scoped_refptr<webrtc::VideoCaptureModule> m_module;
CaptureObserver m_captureObserver;
webrtc::VideoCaptureCapability m_capability;
};
(3)修改源文件
关键代码:
//处理点击事件,打开或关闭摄像头
void MainWindow::on_pushButton_clicked()
{
static bool flag=true;
if(flag)
{
webrtc::VideoCaptureModule::DeviceInfo
*device_info_=webrtc::VideoCaptureFactory::CreateDeviceInfo();
char device_name[256];
char unique_name[256];
if(device_info_->GetDeviceName(ui->comboBox->currentIndex(), device_name, 256,
unique_name, 256) !=0)
{
qDebug()<<"info->GetDeviceName error";
return ;
}
m_module =
webrtc::VideoCaptureFactory::Create(unique_name);
if (m_module.get() == NULL)
{
qDebug()<<"webrtc::VideoCaptureFactory::Create error";
return ;
}
m_module->RegisterCaptureDataCallback(&m_captureObserver);
device_info_->GetCapability(m_module->CurrentDeviceName(), 0, m_capability);
//开始捕捉
if(m_module->StartCapture(m_capability)!=0)
{
qDebug()<<"m_module->StartCapture failed";
return;
}
if(m_module->CaptureStarted())
{
qDebug()<<"Capture is running";
}
m_timer.start(40);
ui->pushButton->setText(tr("关闭"));
}
else
{
ui->pushButton->setText(tr("打开"));
m_timer.stop();
//重复连接会报错,需要先断开,才能再次连接
m_module->StopCapture();
if(!m_module->CaptureStarted())
{
qDebug()<<"Capture is stoped";
}
ui->label->clear();
}
flag=!flag;
}
//初始化界面上的设备列表
void MainWindow::getDeviceList()
{
webrtc::VideoCaptureModule::DeviceInfo
*info=webrtc::VideoCaptureFactory::CreateDeviceInfo();
int deviceNum=info->NumberOfDevices();
for (int i = 0; i < deviceNum; ++i)
{
const uint32_t kSize = 256;
char name[kSize] = {0};
char id[kSize] = {0};
if (info->GetDeviceName(i, name, kSize, id, kSize) != -1)
{
ui->comboBox->addItem(QString(name));
}
}
if(deviceNum==0)
{
ui->pushButton->setEnabled(false);
}
}
二、运行结果
若正常运行,并打开摄像头,会显示如下,这是同事送的点心和饮料(PS.其实是太凉了,我喝不下)
注:
笔者在测试时发现,若是关闭摄像头后,立即打开,可能会打开失败,所以请读者自行处理
后记:
谢谢同事的关心,但也希望对方放松下,不用一天两次的关照(项目)
本次记录的是摄像头相关的,下次计划研究下本地音频相关的