较新的WebRTC源代码中已经没有了与VoiceEngine结构相应的VidoeEngine了,取而代之的是MeidaEngine。MediaEngine包括了MediaEngineInterface接口及事实上现CompositeMediaEngine,CompositeMediaEngine本身也是个模板类,两个模板參数各自是音频引擎和视频引擎。CompositeMediaEngine派生类WebRtcMediaEngine依赖的模板參数是WebRtcVoiceEngine和WebRtcVideoEngine2。

上图中base文件夹中是一些抽象类。engine文件夹中是相应抽象类的实现,使用时直接调用engine文件夹中的接口就可以。WebRtcVoiceEngine实际上是VoiceEngine的再次封装。它使用VoiceEngine进行音频处理。

注意命名,WebRtcVideoEngine2带了个2字,不用想,这肯定是个升级版本号的VideoEngine,还有个WebRtcVideoEngine类。

WebRtcVideoEngine2比WebRtcVideoEngine改进之处在于将视频流一分为二:发送流(WebRtcVideoSendStream)和接收流(WebRtcVideoReceiveStream),从而结构上更合理。源代码更清晰。

       本文的实现主要是使用了WebRtcVideoEngine2中WebRtcVideoCapturer类。

一.环境

參考上篇:WebRTC学习之三:录音和播放

二.实现

        打开WebRtcVideoCapturer的头文件webrtcvideocapture.h。公有的函数基本上都是base文件夹中VideoCapturer类的实现,用于初始化设备和启动捕捉。私有函数OnIncomingCapturedFrame和OnCaptureDelayChanged会在摄像头採集模块VideoCaptureModeule中回调。将採集的图像传给OnIncomingCapturedFrame,并将採集的延时变化传给OnCaptureDelayChanged。

        WebRTC中也实现了类似Qt中的信号和槽机制,详见WebRTC学习之七:精炼的信号和槽机制 。可是就像在该文中提到的,sigslot.h中的emit函数名会和Qt中的emit宏冲突。我将sigslot.h中的emit改成了Emit,当然改完之后,须要又一次编译rtc_baseproject。

VideoCapturer类有两个信号sigslot::signal2<VideoCapturer*, CaptureState> SignalStateChange和sigslot::signal2<VideoCapturer*, const CapturedFrame*, sigslot::multi_threaded_local> SignalFrameCaptured,从SignalFrameCaptured的參数能够看出我们仅仅要实现相应的槽函数就能获取到CapturedFrame,在槽函数中将
CapturedFrame进行转换显示就可以。SignalStateChange信号的參数CaptureState是个枚举。标识捕捉的状态(停止、開始、正在进行、失败)。

        信号SignalFrameCaptured正是在回调函数OnIncomingCapturedFrame中发射出去的。

OnIncomingCapturedFrame里面用到了函数的异步运行。详见WebRTC学习之八:函数的异步运行

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H #include <QMainWindow>
#include <QDebug> #include <map>
#include <memory>
#include <string> #include "webrtc/base/sigslot.h"
#include "webrtc/modules/video_capture/video_capture.h"
#include "webrtc/modules/video_capture/video_capture_factory.h"
#include "webrtc/media/base/videocapturer.h"
#include "webrtc/media/engine/webrtcvideocapturer.h"
#include "webrtc/media/engine/webrtcvideoframe.h" namespace Ui {
class MainWindow;
} class MainWindow : public QMainWindow,public sigslot::has_slots<>
{
Q_OBJECT public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void OnFrameCaptured(cricket::VideoCapturer* capturer, const cricket::CapturedFrame* frame);
void OnStateChange(cricket::VideoCapturer* capturer, cricket::CaptureState state); private slots:
void on_pushButtonOpen_clicked(); private:
void getDeviceList(); private:
Ui::MainWindow *ui;
cricket::WebRtcVideoCapturer *videoCapturer;
cricket::WebRtcVideoFrame *videoFrame;
std::unique_ptr<uint8_t[]> videoImage;
QStringList deviceNameList;
QStringList deviceIDList;
}; #endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
videoCapturer(new cricket::WebRtcVideoCapturer()),
videoFrame(new cricket::WebRtcVideoFrame())
{
ui->setupUi(this);
getDeviceList();
} MainWindow::~MainWindow()
{
delete ui;
videoCapturer->SignalFrameCaptured.disconnect(this);
videoCapturer->SignalStateChange.disconnect(this);
videoCapturer->Stop();
} void MainWindow::OnFrameCaptured(cricket::VideoCapturer* capturer,const cricket::CapturedFrame* frame)
{ videoFrame->Init(frame, frame->width, frame->height,true);
//将视频图像转成RGB格式
videoFrame->ConvertToRgbBuffer(cricket::FOURCC_ARGB,
videoImage.get(),
videoFrame->width()*videoFrame->height()*32/8,
videoFrame->width()*32/8); QImage image(videoImage.get(), videoFrame->width(), videoFrame->height(), QImage::Format_RGB32);
ui->label->setPixmap(QPixmap::fromImage(image));
} void MainWindow::OnStateChange(cricket::VideoCapturer* capturer, cricket::CaptureState state)
{ } void MainWindow::getDeviceList()
{
deviceNameList.clear();
deviceIDList.clear();
webrtc::VideoCaptureModule::DeviceInfo *info=webrtc::VideoCaptureFactory::CreateDeviceInfo(0);
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)
{
deviceNameList.append(QString(name));
deviceIDList.append(QString(id));
ui->comboBoxDeviceList->addItem(QString(name));
}
} if(deviceNum==0)
{
ui->pushButtonOpen->setEnabled(false);
}
} void MainWindow::on_pushButtonOpen_clicked()
{
static bool flag=true;
if(flag)
{
ui->pushButtonOpen->setText(QStringLiteral("关闭")); const std::string kDeviceName = ui->comboBoxDeviceList->currentText().toStdString();
const std::string kDeviceId = deviceIDList.at(ui->comboBoxDeviceList->currentIndex()).toStdString(); videoCapturer->Init(cricket::Device(kDeviceName, kDeviceId));
int width=videoCapturer->GetSupportedFormats()->at(0).width;
int height=videoCapturer->GetSupportedFormats()->at(0).height;
cricket::VideoFormat format(videoCapturer->GetSupportedFormats()->at(0));
//開始捕捉
if(cricket::CS_STARTING == videoCapturer->Start(format))
{
qDebug()<<"Capture is started";
}
//连接WebRTC的信号和槽
videoCapturer->SignalFrameCaptured.connect(this,&MainWindow::OnFrameCaptured);
videoCapturer->SignalStateChange.connect(this,&MainWindow::OnStateChange); if(videoCapturer->IsRunning())
{
qDebug()<<"Capture is running";
} videoImage.reset(new uint8_t[width*height*32/8]); }
else
{
ui->pushButtonOpen->setText(QStringLiteral("打开"));
//反复连接会报错,须要先断开,才干再次连接
videoCapturer->SignalFrameCaptured.disconnect(this);
videoCapturer->SignalStateChange.disconnect(this);
videoCapturer->Stop();
if(!videoCapturer->IsRunning())
{
qDebug()<<"Capture is stoped";
}
ui->label->clear();
}
flag=!flag;
}

main.cpp

#include "mainwindow.h"
#include <QApplication> int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
while(true)
{
//WebRTC消息循环
rtc::Thread::Current()->ProcessMessages(0);
rtc::Thread::Current()->SleepMs(1);
//Qt消息循环
a.processEvents( );
}
}

注意main函数中对WebRTC和Qt消息循环的处理,这是用Qt调用WebRTC进行摄像头捕捉和显示的关键。

三.效果

WebRTC学习之九:摄像头的捕捉和显示的更多相关文章

  1. WebRTC学习笔记_Demo收集

    1.     WebRTC学习 1.1   WebRTC现状 本人最早接触WebRTC是在2011年底,那时Google已经在Android源代码中增加了webrtc源代码,放在/external/w ...

  2. WebRTC学习

    1.     WebRTC学习 1.1   WebRTC现状 本人最早接触WebRTC是在2011年底,那时Google已经在Android源码中加入了webrtc源码,放在/external/web ...

  3. WebRTC学习与DEMO资源一览

    一. WebRTC学习 1.1   WebRTC现状 本人最早接触WebRTC是在2011年底,那时Google已经在Android源码中加入了webrtc源码,放在/external/webrtc/ ...

  4. [转]webrtc学习: 部署stun和turn服务器

    [转]webrtc学习: 部署stun和turn服务器 http://www.cnblogs.com/lingdhox/p/4209659.html webrtc的P2P穿透部分是由libjingle ...

  5. 【转载】 强化学习(九)Deep Q-Learning进阶之Nature DQN

    原文地址: https://www.cnblogs.com/pinard/p/9756075.html ------------------------------------------------ ...

  6. 多线程学习笔记九之ThreadLocal

    目录 多线程学习笔记九之ThreadLocal 简介 类结构 源码分析 ThreadLocalMap set(T value) get() remove() 为什么ThreadLocalMap的键是W ...

  7. (转)Maven学习总结(九)——使用Nexus搭建Maven私服

    孤傲苍狼只为成功找方法,不为失败找借口! Maven学习总结(九)——使用Nexus搭建Maven私服 一.搭建nexus私服的目的 为什么要搭建nexus私服,原因很简单,有些公司都不提供外网给项目 ...

  8. MDX导航结构层次:《Microsoft SQL Server 2008 MDX Step by Step》学习笔记九

    <Microsoft SQL Server 2008 MDX Step by Step>学习笔记九:导航结构层次   SQL Server 2008中SQL应用系列及BI笔记系列--目录索 ...

  9. python3.4学习笔记(九) Python GUI桌面应用开发工具选择

    python3.4学习笔记(九) Python GUI桌面应用开发工具选择 Python GUI开发工具选择 - WEB开发者http://www.admin10000.com/document/96 ...

随机推荐

  1. OpenOCD 0.9.0 release

    OpenOCD 0.9.0 release May 18th, 2015 I’m happy to announce the release of OpenOCD version 0.9.0, fin ...

  2. 通过webbrowser控件获取验证码

    1.首先介绍下基本控件(拖控件大家都会,我就不一一介绍了),看下图: 2.添加MSHTML引用,步骤如下: 解决方案—右键“引用”—​添加引用—在.NET下找到Microsoft.mshtml组件—点 ...

  3. linux C宏定义 转

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等.下面列举一些成熟软件中常用得宏定义...... 1,防止一个头文件被重复包含 #ifndef COMDEF_H ...

  4. 解决Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COER

    今天在用java与mysql数据库时发现Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COER ...

  5. 为什么你的session不见了

    一:现象 有小伙伴写了下面一段代码,然后发现,随着每次关闭浏览器,count的值重新开始计数了,如下: protected void doGet(HttpServletRequest request, ...

  6. Caffe常用层参数介绍

    版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/Cheese_pop/article/details/52024980 DATA crop:截取原图像中一个 ...

  7. Python 模块 re (Regular Expression)

    使用 Python 模块 re 实现解析小工具   概要 在开发过程中发现,Python 模块 re(Regular Expression)是一个很有价值并且非常强大的文本解析工具,因而想要分享一下此 ...

  8. DPI (Deep Packet Inspection) 深度包检测技术

    详解DPI与网络回溯分析技术 随着网络通讯技术进步与发展,网络通讯已跨入大数据时代,如何监控各类业务系统的通讯数据在大数据流量中传输质量,以及针对海量的网络通讯数据的范畴中存在少量的恶意流量的检测,避 ...

  9. [转]XCache 3.0.0 发布,PHP 性能提升方案

    From : http://www.oschina.net/news/34304/xcache-3-0-0 XCache 3.0.0 发布,该版本除了 bug 修复,对 XCache 管理页面做了很多 ...

  10. TFS中查看我的所有签入迁出记录 TFS 怎么查看所有的修改

    [源代码资源管理器]=>左边窗口目录树选中一行项目=>右键 查看历史记录=>在历史记录中,双击变更集即可以看到某一次变更的所有记录.