当前位置: 首页 > news >正文

基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备

一、前言说明

这个功能是之前写的监控设备模拟器的衍生,同时集成在该项目中,就是单独写个竖版的app样式的界面,然后编译成安卓版本即可,默认就模拟一路设备,从设备地址下拉框中选择安卓摄像头即可,所有的底层功能使用的就是设备模拟器的,为何会有这个需求?之前的模拟器已经可以将任意的视频文件视频流,以及本地USB摄像头或者桌面采集,转成监控设备,通过onvif协议或者28181协议,和服务端平台端进行交互,当时设计的时候就已经考虑到了跨平台的场景,所以其实这些底层组件代码是完全支持安卓的,为了使得ffmpeg能够正常采集到安卓摄像头,当时还特意搞了很久,编译带avdevice的ffmpeg安卓库,网上几乎都是不带avdevice的,搞得之前还以为代码有问题,原来是对应的库没有带。

目前在手机上只是采集了摄像头的实时视频画面,音频这块还没有实现,在win上使用dshow采集麦克风,在linux上使用alsa采集麦克风,到安卓上目前没有发现有对应的实现,所以也挺鸡肋的,后期估计先采用Qt的麦克风采集,相当于单独音频交互,如果是ffmpeg推流rtsp的话,还要涉及到混流,也就是之前的视频流需要加上采集的音频流,混合后再一起推流。

二、效果图

video_simulate_app_28181

video_simulate_app_onvif

video_simulate_gb3

三、相关地址

  1. 国内站点:https://gitee.com/feiyangqingyun
  2. 国际站点:https://github.com/feiyangqingyun
  3. 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_simulate。

四、功能特点

  1. 标准onvif协议,支持设备搜索、获取参数、快照抓图等。
  2. 支持264/265/aac等标准视音频协议传输。
  3. 支持多路批量onvif设备模拟,每一路都独立的端口。
  4. 支持本地摄像头采集转成onvif,可选择不同的设备、分辨率、帧率等参数。
  5. 支持本地桌面采集转成onvif,可选择不同的屏幕、分辨率、帧率等参数。
  6. 支持各种视频文件和视频流转成onvif,可重新设置编码转换以及分辨率转换。
  7. 支持4K、8K等高清分辨率,不限制分辨率,非264/265会自动转码推流。
  8. 每一路都可以设置统一或者独立的用户验证信息,为空则表示不验证。
  9. 可以把任意内容接入到NVR以及视频监控系统,方便保存录像文件,以便回放可查。
  10. 也可作为压力测试工具,比如模拟几千路onvif设备,让集成平台软件做接入压力测试。
  11. 推出去的流不仅有rtsp格式,还支持rtmp、http、flv、ws-flv、webrtc等方式访问,可以直接网页查看。
  12. 在管理工具上可以看到每一路的推流状况以及分辨率信息,非常直观。
  13. 支持自动重连拉流,重连推流,保证7乘以24小时稳定运行。
  14. 可设置开机自启动运行和后台运行,不显示在任务栏,作为后台服务运行。
  15. 可批量添加文件、添加目录,自动将目录下的所有文件添加到模拟器。
  16. 多功能添加地址面板,可以选择本地设备和监控设备,本地设备会自动识别摄像头设备和桌面设备,监控设备可以选择不同厂家,自动填充对应rtsp格式,填入用户信息即可,可以批量递增添加监控设备。
  17. 可无缝上传到市面上所有的onvif协议设备,包括海康、大华、宇视、华为、天地伟业等,也支持ONVIF Device Manager国际onvif工具。
  18. 支持gb28181设备模拟,具备设备注册、设备注销、设备心跳、设备信息、设备配置、设备状态应答等。
  19. 支持模拟报警和位置上报等,方便平台侧显示对应设备的实时位置。
  20. 支持一键添加批量模拟28181设备,实时显示已注册和已注销状态。
  21. 支持将本地桌面、本地摄像头、任意视频文件、视频流文件、手机摄像头等转换成28181设备,添加到NVR或者国标软件平台。
  22. sip协议同时支持udp和tcp两种通信方式,视频点播同时支持udp/tcp主动/tcp被动三种方式,涵盖所有可能的场景需求。
  23. 无论是onvif设备模拟组件还是28181设备模拟组件,全部原创底层协议解析,纯Qt实现,跨任意平台。
  24. 代码结构框架非常清晰,注释详细,代码精简不繁琐,非常易于学习和移植,可以很容易拓展其他接口需求。
  25. 支持Qt4/Qt5/Qt6以及后续所有版本、所有编译器、所有开发环境。
  26. 支持windows、linux、mac、国产OS、嵌入式linux、RK3588、树莓派、香橙派等系统。

五、相关代码

#include "frmonvifapp.h"
#include "ui_frmonvifapp.h"
#include "qthelper.h"
#include "videoutil.h"
#include "urlutil.h"
#include "onvifdevicepush.h"
#include "onvifdeviceserver.h"frmOnvifApp::frmOnvifApp(QWidget *parent) : QWidget(parent), ui(new Ui::frmOnvifApp)
{ui->setupUi(this);this->initForm();this->initConfig();
}frmOnvifApp::~frmOnvifApp()
{server->stop();delete ui;
}void frmOnvifApp::initForm()
{//设置开启解码/需要解码后在这里显示OnvifDevicePush::disableDecode = false;//实例化设备服务类并关联信号槽server = new OnvifDeviceServer(this);connect(server, SIGNAL(pushImage(QString, QImage)), this, SLOT(pushImage(QString, QImage)));server->start();QStringList ips;ips << QtHelper::getLocalIPs();ui->cboxServerIp->addItems(ips);//不存在则取第一个int index = ui->cboxServerIp->findText(AppConfig::OnvifServerIp);if (index < 0) {QString ip = ips.first();AppConfig::OnvifServerIp = ip;AppConfig::OnvifServerHost = ip;AppConfig::OnvifPushHost = ip;}
}void frmOnvifApp::initConfig()
{VideoUtil::loadMediaUrl(ui->cboxMediaUrl, AppConfig::OnvifMediaUrl, UrlUtil::Simple);connect(ui->cboxMediaUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->cboxServerIp->lineEdit()->setText(AppConfig::OnvifServerIp);connect(ui->cboxServerIp->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));connect(ui->cboxServerIp->lineEdit(), SIGNAL(textChanged(QString)), ui->txtServerHost, SLOT(setText(QString)));connect(ui->cboxServerIp->lineEdit(), SIGNAL(textChanged(QString)), ui->txtPushHost, SLOT(setText(QString)));ui->txtServerHost->setText(AppConfig::OnvifServerHost);connect(ui->txtServerHost, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtUserName->setText(AppConfig::OnvifUserName);connect(ui->txtUserName, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtUserPwd->setText(AppConfig::OnvifUserPwd);connect(ui->txtUserPwd, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtPushFlag->setText(AppConfig::OnvifPushFlag);connect(ui->txtPushFlag, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtPushHost->setText(AppConfig::OnvifPushHost);connect(ui->txtPushHost, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtPushPort->setText(QString::number(AppConfig::OnvifPushPort));connect(ui->txtPushPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtListenPort->setText(QString::number(AppConfig::OnvifListenPort));connect(ui->txtListenPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
}void frmOnvifApp::saveConfig()
{AppConfig::OnvifMediaUrl = ui->cboxMediaUrl->lineEdit()->text().trimmed();AppConfig::OnvifServerHost = ui->txtServerHost->text().trimmed();AppConfig::OnvifServerIp = ui->cboxServerIp->lineEdit()->text().trimmed();AppConfig::OnvifUserName = ui->txtUserName->text().trimmed();AppConfig::OnvifUserPwd = ui->txtUserPwd->text().trimmed();AppConfig::OnvifPushFlag = ui->txtPushFlag->text().trimmed();AppConfig::OnvifPushHost = ui->txtPushHost->text().trimmed();AppConfig::OnvifPushPort = ui->txtPushPort->text().toInt();AppConfig::OnvifListenPort = ui->txtListenPort->text().toInt();AppConfig::writeConfig();
}void frmOnvifApp::pushImage(const QString &, const QImage &image)
{if (ui->btnStart->text() == "停止服务") {ui->labImage->setImage(image, true);} else {ui->labImage->clear();}
}void frmOnvifApp::on_btnStart_clicked()
{if (ui->btnStart->text() == "启动服务") {        QString rtspUrl = QString("rtsp://%1:%2/stream/%3").arg(AppConfig::OnvifPushHost).arg(AppConfig::OnvifPushPort).arg(AppConfig::OnvifPushFlag);server->setPara(AppConfig::OnvifServerHost, AppConfig::OnvifServerIp, AppConfig::OnvifUserName, AppConfig::OnvifUserPwd);bool ok = server->append(AppConfig::OnvifPushFlag, AppConfig::OnvifListenPort, AppConfig::OnvifMediaUrl, rtspUrl);if (ok) {ui->txtPushUrl->setText(rtspUrl);ui->frame->setEnabled(false);ui->btnStart->setText("停止服务");}} else {server->clear();ui->labImage->clear();ui->txtPushUrl->clear();ui->frame->setEnabled(true);ui->btnStart->setText("启动服务");}
}#include "frmgb28181app.h"
#include "ui_frmgb28181app.h"
#include "qthelper.h"
#include "videoutil.h"
#include "urlutil.h"
#include "gb28181deviceserver.h"
#include "gb28181devicepush.h"frmGB28181App::frmGB28181App(QWidget *parent) : QWidget(parent), ui(new Ui::frmGB28181App)
{ui->setupUi(this);this->initForm();this->initConfig();
}frmGB28181App::~frmGB28181App()
{server->stop();delete ui;
}void frmGB28181App::initForm()
{//设置开启解码/需要解码后在这里显示GB28181DevicePush::disableDecode = false;//实例化设备服务类并关联信号槽server = new GB28181DeviceServer(this);connect(server, SIGNAL(statusChanged(QString, int)), this, SLOT(statusChanged(QString, int)));connect(server, SIGNAL(pushImage(QString, QImage)), this, SLOT(pushImage(QString, QImage)));server->start();QStringList ips;ips << QtHelper::getLocalIPs();ui->cboxDeviceIp->addItems(ips);//不存在则取第一个int index = ui->cboxDeviceIp->findText(AppConfig::GB28181DeviceIp);if (index < 0) {AppConfig::GB28181DeviceIp = ips.first();}
}void frmGB28181App::initConfig()
{VideoUtil::loadMediaUrl(ui->cboxMediaUrl, AppConfig::GB28181MediaUrl, UrlUtil::Simple);connect(ui->cboxMediaUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->cboxSipProtocol->setCurrentIndex(ui->cboxSipProtocol->findText(AppConfig::GB28181SipProtocol));connect(ui->cboxSipProtocol, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));ui->txtServerId->setText(AppConfig::GB28181ServerId);connect(ui->txtServerId, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtServerRealm->setText(AppConfig::GB28181ServerRealm);connect(ui->txtServerRealm, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtServerIp->setText(AppConfig::GB28181ServerIp);connect(ui->txtServerIp, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtServerPort->setText(QString::number(AppConfig::GB28181ServerPort));connect(ui->txtServerPort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtServerPwd->setText(AppConfig::GB28181ServerPwd);connect(ui->txtServerPwd, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->cboxDeviceIp->lineEdit()->setText(AppConfig::GB28181DeviceIp);connect(ui->cboxDeviceIp->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtDevicePort->setText(QString::number(AppConfig::GB28181DevicePort));connect(ui->txtDevicePort, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtDeviceId->setText(AppConfig::GB28181DeviceId);connect(ui->txtDeviceId, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtChannelId->setText(AppConfig::GB28181ChannelId);connect(ui->txtChannelId, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtRegistInterval->setText(QString::number(AppConfig::GB28181RegistInterval));connect(ui->txtRegistInterval, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtHeartInterval->setText(QString::number(AppConfig::GB28181HeartInterval));connect(ui->txtHeartInterval, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));ui->txtHeartTimeout->setText(QString::number(AppConfig::GB28181HeartTimeout));connect(ui->txtHeartTimeout, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
}void frmGB28181App::saveConfig()
{AppConfig::GB28181MediaUrl = ui->cboxMediaUrl->lineEdit()->text().trimmed();AppConfig::GB28181SipProtocol = ui->cboxSipProtocol->currentText();AppConfig::GB28181ServerId = ui->txtServerId->text().trimmed();AppConfig::GB28181ServerRealm = ui->txtServerRealm->text().trimmed();AppConfig::GB28181ServerIp = ui->txtServerIp->text().trimmed();AppConfig::GB28181ServerPort = ui->txtServerPort->text().toInt();AppConfig::GB28181ServerPwd = ui->txtServerPwd->text().trimmed();AppConfig::GB28181DeviceIp = ui->cboxDeviceIp->lineEdit()->text().trimmed();AppConfig::GB28181DevicePort = ui->txtDevicePort->text().toInt();AppConfig::GB28181DeviceId = ui->txtDeviceId->text().trimmed();AppConfig::GB28181ChannelId = ui->txtChannelId->text().trimmed();AppConfig::GB28181RegistInterval = ui->txtRegistInterval->text().toInt();AppConfig::GB28181HeartInterval = ui->txtHeartInterval->text().toInt();AppConfig::GB28181HeartTimeout = ui->txtHeartTimeout->text().toInt();AppConfig::writeConfig();
}void frmGB28181App::statusChanged(const QString &id, int status)
{QString text = (status == 1 ? "已注册" : "已注销");ui->labImage->setText(text);
}void frmGB28181App::pushImage(const QString &, const QImage &image)
{if (ui->btnStart->text() == "停止服务") {ui->labImage->setImage(image, true);} else {ui->labImage->clear();}
}void frmGB28181App::on_btnStart_clicked()
{if (ui->btnStart->text() == "启动服务") {server->setPara(AppConfig::GB28181ServerId, AppConfig::GB28181ServerRealm, AppConfig::GB28181ServerIp, AppConfig::GB28181ServerPort, AppConfig::GB28181ServerPwd, AppConfig::GB28181RegistInterval, AppConfig::GB28181HeartInterval, AppConfig::GB28181HeartTimeout);bool ok = server->append(AppConfig::GB28181SipProtocol, AppConfig::GB28181DeviceIp, AppConfig::GB28181DevicePort, AppConfig::GB28181DeviceId, AppConfig::GB28181ChannelId, AppConfig::GB28181MediaUrl);if (ok) {ui->frame->setEnabled(false);ui->btnStart->setText("停止服务");}} else {server->clear();ui->labImage->clear();ui->frame->setEnabled(true);ui->btnStart->setText("启动服务");}
}void frmGB28181App::on_btnUpdate_clicked()
{server->update();server->catalog();
}
http://www.hskmm.com/?act=detail&tid=16577

相关文章:

  • 详细介绍:Flink 2.x 独立集群(Standalone) 的部署
  • 瑞芯微RK3506核心板/开发板DSM音频开发实战,关键知识点与实操案例必看攻略! - 教程
  • 不只是一台玩具车:开源燃料电池机器人HydroBot全揭秘 - 实践
  • 在AI技术唾手可得的时代,挖掘新需求成为核心竞争力——某知名窗口管理工具需求洞察
  • OS-KylinV10-加载动态库运行异常-全局函数重名或未使用命名空间
  • 性能暴涨50%:PD分离KV cache传输的实战干货
  • 【GitHub每日速递 250925】 一套代码跑遍全平台!Flutter 让你的应用开发提速 10 倍
  • 上海芯片上市公司市值大揭秘!谁是“芯”界顶流?
  • 中科微卫星定位芯片代理商,北斗双频定位导航模组ATGM332D-F7N
  • 四个第一!又一国产GPU突围亮相!
  • AI智慧:于悬荡中并行,在悟空里觉醒
  • 读人形机器人22工作的意义
  • .NET 何以成为制造业数字化转型的基石:效率、生态与跨平台的制胜之道
  • 深度互联:金兰契协议下的领域知识与元智慧共生
  • Winform无边框窗体拖动功能实现
  • HarmonyOS SDK 媒体开放能力在微博社交场景的实践剖析
  • 今天我看了
  • reaction 记录——《彻夜之歌》
  • 孤独 寂寞
  • 泰勒展开中的佩亚诺余项与高阶无穷小:不只是“小到可以忽略”
  • 关于“屏蔽词”的历史遗传
  • 不变应万变
  • [智能驾驶/智能汽车] 《SAE J3016-202104:驾驶自动化分级》[转]
  • [汽车] 智能网联汽车-智能驾驶-综述
  • 【stm32-FOC】初步认识 CMSIS-DSP
  • 护照包 阻门器 防偷包
  • Python-Conda技术指南
  • [GRPC]基于C#和GO 的GRPC快速上手
  • 19.并发编程
  • 复健