247 lines
8.8 KiB
C++
247 lines
8.8 KiB
C++
#include "P10_IntelligentPage.h"
|
||
#include "ui_P10_IntelligentPage.h"
|
||
#include <QScrollArea>
|
||
#include <QScrollBar>
|
||
#include <QDebug>
|
||
#include <QString>
|
||
|
||
// 构造函数:初始化UI与播放器
|
||
P10_IntelligentPage::P10_IntelligentPage(QWidget *parent) :
|
||
QWidget(parent),
|
||
ui(new Ui::P10_IntelligentPage)
|
||
{
|
||
ui->setupUi(this);
|
||
#if CONFIG_EN_RTSP //开启 RTSP 读取
|
||
m_rtspPlayer = new RtspPlayer(this);// 初始化RTSP播放器(父对象绑定,避免内存泄漏)
|
||
QTimer::singleShot(1000, this, &P10_IntelligentPage::WinInit); // 调用初始化函数
|
||
#endif
|
||
}
|
||
|
||
// 析构函数:释放资源
|
||
P10_IntelligentPage::~P10_IntelligentPage()
|
||
{
|
||
#if CONFIG_EN_RTSP //开启 RTSP 读取
|
||
// 停止RTSP播放并释放播放器资源
|
||
if (m_rtspPlayer != nullptr) {
|
||
m_rtspPlayer->stopPlay();
|
||
m_rtspPlayer->wait(); // 等待播放线程完全退出,避免资源冲突
|
||
}
|
||
#endif
|
||
delete ui; // 释放UI对象
|
||
}
|
||
#if CONFIG_EN_RTSP //开启 RTSP 读取
|
||
// 界面与逻辑初始化
|
||
void P10_IntelligentPage::WinInit()
|
||
{
|
||
// 配置视频显示区域(绑定到ScrollArea,支持缩放后滚动)
|
||
ui->videoLabel->setParent(nullptr); // 解除原有父控件绑定
|
||
ui->scrollArea->setWidget(ui->videoLabel); // 将videoLabel设为ScrollArea的内容控件
|
||
ui->scrollArea->setWidgetResizable(false); // 禁用自动调整大小(手动控制缩放)
|
||
ui->videoLabel->installEventFilter(this); // 为videoLabel安装事件过滤器(处理拖拽)
|
||
ui->videoLabel->setAlignment(Qt::AlignCenter); // 视频帧居中显示
|
||
ui->Label_Zoom->setText("100 %"); // 初始化缩放比例显示(补充百分号,更直观)
|
||
|
||
// 连接RTSP播放器信号槽(帧接收、错误提示)
|
||
connect(m_rtspPlayer, &RtspPlayer::frameReady,
|
||
this, &P10_IntelligentPage::onFrameReady);
|
||
connect(m_rtspPlayer, &RtspPlayer::errorOccurred,
|
||
this, &P10_IntelligentPage::onErrorOccurred);
|
||
|
||
// 默认加载第一个摄像头
|
||
on_But_Atlas_1_clicked();
|
||
}
|
||
|
||
// 设置RTSP地址(外部调用接口,可选)
|
||
void P10_IntelligentPage::setRtspUrl(const QString &url)
|
||
{
|
||
m_rtspUrl = url;
|
||
}
|
||
|
||
void P10_IntelligentPage::on_But_Atlas_1_clicked()
|
||
{
|
||
// 1. 强制停止播放并等待线程退出(关键)
|
||
m_rtspPlayer->stopPlay();
|
||
if (m_rtspPlayer->isRunning()) {
|
||
ui->videoLabel->setText("正在释放资源...");
|
||
if (!m_rtspPlayer->wait(1000)) { // 最多等待1秒
|
||
qWarning() << "旧线程未正常退出,强制终止";
|
||
}
|
||
}
|
||
|
||
// 2. 重置参数(同之前逻辑)
|
||
Img_Zoom = 1.0f;
|
||
Img_W = 900;
|
||
Img_H = 576;
|
||
ui->scrollArea->resize(Img_W, Img_H);
|
||
ui->videoLabel->resize(Img_W, Img_H);
|
||
ui->videoLabel->setAlignment(Qt::AlignCenter);
|
||
ui->Label_Zoom->setText("100 %");
|
||
ui->But_Atlas_3->setText("暂停");
|
||
|
||
// 3. 延迟初始化新流(延长延迟到800ms,确保资源释放)
|
||
m_rtspUrl = RTSP_Url;
|
||
QTimer::singleShot(800, this, [=]() {
|
||
ui->videoLabel->setText("正在连接实物图摄像头...");
|
||
if (m_rtspPlayer->init(m_rtspUrl)) {
|
||
m_rtspPlayer->startPlay();
|
||
} else {
|
||
ui->videoLabel->setText("摄像头1连接失败\n请检查地址/网络");
|
||
}
|
||
});
|
||
}
|
||
|
||
// 切换到摄像头2(RTSP地址2)
|
||
void P10_IntelligentPage::on_But_Atlas_2_clicked()
|
||
{
|
||
// 1. 强制停止播放并等待线程退出(关键)
|
||
m_rtspPlayer->stopPlay();
|
||
if (m_rtspPlayer->isRunning()) {
|
||
ui->videoLabel->setText("正在释放资源...");
|
||
if (!m_rtspPlayer->wait(1000)) { // 最多等待1秒
|
||
qWarning() << "旧线程未正常退出,强制终止";
|
||
}
|
||
}
|
||
|
||
// 2. 重置参数(同之前逻辑)
|
||
Img_Zoom = 1.0f;
|
||
Img_W = 800;
|
||
Img_H = 576;
|
||
ui->scrollArea->resize(Img_W, Img_H);
|
||
ui->videoLabel->resize(Img_W, Img_H);
|
||
ui->Label_Zoom->setText("100 %");
|
||
ui->But_Atlas_3->setText("暂停");
|
||
|
||
// 3. 设置摄像头2的RTSP地址并延迟初始化
|
||
m_rtspUrl = "rtsp://admin:sshw1212@192.168.1.64:554/Streaming/Channels/201";
|
||
QTimer::singleShot(800, this, [=]() {
|
||
ui->videoLabel->setText("正在连接热力图摄像头...");
|
||
if (m_rtspPlayer->init(m_rtspUrl)) {
|
||
m_rtspPlayer->startPlay();
|
||
} else {
|
||
ui->videoLabel->setText("摄像头1连接失败\n请检查地址/网络");
|
||
}
|
||
});
|
||
}
|
||
|
||
// 暂停/继续播放(切换按钮文本与播放状态)
|
||
void P10_IntelligentPage::on_But_Atlas_3_clicked()
|
||
{
|
||
// 检查播放器是否已初始化(避免空操作)
|
||
if (!m_rtspPlayer->isRunning()) {
|
||
ui->videoLabel->setText("未连接摄像头\n无法操作");
|
||
return;
|
||
}
|
||
|
||
if (ui->But_Atlas_3->text() == "继续") {
|
||
ui->But_Atlas_3->setText("暂停");
|
||
m_rtspPlayer->startPlay(); // 继续播放
|
||
} else {
|
||
ui->But_Atlas_3->setText("继续");
|
||
m_rtspPlayer->pausePlay(); // 暂停播放
|
||
}
|
||
}
|
||
|
||
// 图像放大(步长0.1,最大5倍)
|
||
void P10_IntelligentPage::on_But_Magnify_clicked()
|
||
{
|
||
if (Img_Zoom >= 5.0f) return; // 限制最大缩放比例
|
||
|
||
Img_Zoom += 0.1f;
|
||
// 格式化缩放比例显示(保留2位小数,加百分号)
|
||
ui->Label_Zoom->setText(QString::asprintf("%.0f %%", Img_Zoom * 100));
|
||
// 计算并调整视频Label大小(用qRound避免浮点数精度问题)
|
||
int newW = qRound(Img_W * Img_Zoom);
|
||
int newH = qRound(Img_H * Img_Zoom);
|
||
ui->videoLabel->resize(newW, newH);
|
||
}
|
||
|
||
// 图像缩小(步长0.1,最小1倍)
|
||
void P10_IntelligentPage::on_But_Reduce_clicked()
|
||
{
|
||
if (Img_Zoom <= 1.0f) return; // 限制最小缩放比例(不小于原始尺寸)
|
||
|
||
Img_Zoom -= 0.1f;
|
||
ui->Label_Zoom->setText(QString::asprintf("%.0f %%", Img_Zoom * 100));
|
||
int newW = qRound(Img_W * Img_Zoom);
|
||
int newH = qRound(Img_H * Img_Zoom);
|
||
ui->videoLabel->resize(newW, newH);
|
||
}
|
||
|
||
// 接收新视频帧,转换为QPixmap并显示
|
||
void P10_IntelligentPage::onFrameReady(const QImage &frame)
|
||
{
|
||
if(gPageIndexStr != "P10")
|
||
return;
|
||
if (frame.isNull()) return; // 过滤空帧,避免无效操作
|
||
|
||
// 缩放帧图像(保持宽高比,填充Label,平滑缩放)
|
||
QPixmap pixmap = QPixmap::fromImage(frame).scaled(
|
||
ui->videoLabel->size(),
|
||
Qt::KeepAspectRatioByExpanding, // 按比例填充Label(不拉伸变形)
|
||
Qt::SmoothTransformation // 平滑缩放,提升画质
|
||
);
|
||
ui->videoLabel->setPixmap(pixmap);
|
||
}
|
||
|
||
// 接收错误信息,显示到视频Label并打印调试日志
|
||
void P10_IntelligentPage::onErrorOccurred(const QString &msg)
|
||
{
|
||
qDebug() << "[P10_IntelligentPage 摄像头错误]:" << msg;
|
||
// 在视频区域显示错误信息(换行优化显示)
|
||
ui->videoLabel->setText(QString("错误:\n%1").arg(msg));
|
||
ui->videoLabel->setPixmap(QPixmap()); // 清除当前显示的图像
|
||
}
|
||
|
||
// 事件过滤器:处理videoLabel的鼠标拖拽平移
|
||
bool P10_IntelligentPage::eventFilter(QObject *obj, QEvent *ev)
|
||
{
|
||
// 仅处理videoLabel的事件,且确保有图像显示时才响应拖拽
|
||
if (obj != ui->videoLabel || !ui->videoLabel->pixmap()) {
|
||
return false;
|
||
}
|
||
|
||
switch (ev->type()) {
|
||
case QEvent::MouseButtonPress: {
|
||
QMouseEvent *mouseEv = static_cast<QMouseEvent*>(ev);
|
||
// 仅响应左键按下
|
||
if (mouseEv->button() == Qt::LeftButton) {
|
||
dragging = true;
|
||
dragStart = mouseEv->pos(); // 记录拖拽起始点
|
||
ui->videoLabel->setCursor(Qt::ClosedHandCursor); // 改变鼠标样式(闭合手)
|
||
}
|
||
return true; // 拦截事件,避免向下传递
|
||
}
|
||
|
||
case QEvent::MouseMove: {
|
||
if (!dragging) return false; // 未处于拖拽状态,不处理
|
||
|
||
QMouseEvent *mouseEv = static_cast<QMouseEvent*>(ev);
|
||
// 计算拖拽偏移量
|
||
int dx = mouseEv->pos().x() - dragStart.x();
|
||
int dy = mouseEv->pos().y() - dragStart.y();
|
||
|
||
// 调整ScrollArea的滚动条位置(实现平移)
|
||
QScrollBar *hBar = ui->scrollArea->horizontalScrollBar();
|
||
QScrollBar *vBar = ui->scrollArea->verticalScrollBar();
|
||
hBar->setValue(qBound(hBar->minimum(), hBar->value() - dx, hBar->maximum()));
|
||
vBar->setValue(qBound(vBar->minimum(), vBar->value() - dy, vBar->maximum()));
|
||
|
||
dragStart = mouseEv->pos(); // 更新起始点,准备下一次计算
|
||
return true;
|
||
}
|
||
|
||
case QEvent::MouseButtonRelease: {
|
||
QMouseEvent *mouseEv = static_cast<QMouseEvent*>(ev);
|
||
if (dragging && mouseEv->button() == Qt::LeftButton) {
|
||
dragging = false;
|
||
ui->videoLabel->unsetCursor(); // 恢复默认鼠标样式
|
||
}
|
||
return true;
|
||
}
|
||
|
||
default:
|
||
return false; // 其他事件不拦截,正常传递
|
||
}
|
||
}
|
||
#endif
|