使用Qt搭建的监控平台

目录

视频展示

源码链接

功能介绍

1.登录注册

1.1 图片验证码

1.2 明文密文切换

1.3密码存储

2.监控界面

2.1监控画面

2.2四通道切换

2.3拍照功能

2.4视频定时存储

3.视频回放界面

3.1翻页功能

3.2视频播放

4.照片回放界面

4.1分页功能

4.2照片信息展示

4.3双击放大

5.视频播放

5.1倍速播放

5.2视频暂停

5.4进度条拖动

5.5视频切换

6.日志查看界面

7.设置界面

7.1多选下拉框

7.2摄像头设备获取

联系我


视频展示

监控系统功能展示_哔哩哔哩_bilibili

源码链接

clt123haha/Security (github.com)

如果觉得还不错给个star吧

功能介绍

1.登录注册

1.1 图片验证码

这里是使用了一个博客封装好的部分,暂时找不到原来的链接了,找到了会在这里进行补充

用户输入后与验证码的字符进行比对(大小写无关),大小写无关通过str.toLower () 实现

1.2 明文密文切换

在QPushButton中设置眼睛样式的图片后,链接一个槽函数,在进行点击后进行QlineEdit的模式切换以实现明文密文的切换

1.3密码存储

在信息无误后,将信息进行存储,其中密码以MD5进行加密后存储

2.监控界面

2.1监控画面

获取到设置信息中的摄像头信息,以;为分隔符获取到一个list,依次给与对应的摄像头线程,对捕捉到的信息进行纯净化处理后,将得到的QIamge通过信号发送出去,在绑定的槽函数中保存QIamge,然后触发uodate函数(以激活重绘事件)

2.2四通道切换

设定了一个int来判定状态(0为四通道正常播放,1-4为对应通道画面放大),在重绘事件中进行处理,isvisible可以进行隐藏,这里有一个问题是isvisible和label设置大小的顺序,要先设置label的大小在设置isvisible为true,否则窗口大小肯会受影响

2.3拍照功能

在单通道模式下允许拍照,否则弹窗提示。图片存储路径为:设定图片存储路径/摄像头名称/yymmddmmss.jpg,这里首先会判断有无摄像头文件夹,没有进行创建

2.4视频定时存储

在本次存储开始时,将图片存储下来作为封面。摄像头线程将RGB格式发给播放界面,将YUV格式发给存储线程,这里根据我设定的信息1500帧为一分钟,达到设置的时间后,就写尾帧将视频存储下来。

这里是我的设置

this->picture = av_frame_alloc();
this->picture->width = this->CodecContext->width;
this->picture->height = this->CodecContext->height;
this->picture->format = this->CodecContext->pix_fmt;
this->pictureRGB = av_frame_alloc();
this->pictureRGB->width = this->CodecContext->width;
this->pictureRGB->height = this->CodecContext->height;
this->pictureRGB->format = this->CodecContext->pix_fmt;
this->pictureYUV = av_frame_alloc();
this->pictureYUV->width = this->CodecContext->width;
this->pictureYUV->height = this->CodecContext->height;
this->pictureYUV->format = this->CodecContext->pix_fmt;

对于这里分为两个线程进行的原因:编码解码二者操作AVPacket时可能发生冲突,导致丢帧现象发生

3.视频回放界面

3.1翻页功能

将数据库的数据读取到QList中,点击对应页码后,加载数据

这里比较特殊的是第一页的情况,点击第二页后页码不会刷新,在往后页码才会进行改变

注:这里实测发现如果加载数据量比较大,会出现比较明显的卡顿现象,我的思路是使用limit  + offset进行数据查询,我没有进行过二者的比对,只是一个思路

3.2视频播放

点击右边封面后,弹出视频播放界面,这里播放的原理和捕捉摄像头部分类似,只是准备工作需要做一点修改

这是摄像头的准备部分

fmt=av_find_input_format("dshow");
int res=avformat_open_input(&pFormatContext,cameraName.toUtf8(),fmt,nullptr);

这里是

int res=avformat_open_input(&formatContent,file.toStdString().c_str(), nullptr,nullptr);

4.照片回放界面

4.1分页功能

这里和视频回放界面的分页类似,只不过是把页码部分换成了滚动条,设置步长为1,setMinimum

为0,计算出页码总数,setMaximum为页码总数

4.2照片信息展示

右侧部分从上到下依次显示照片名称、宽、高、大小,这里照片名称可能会过长,导致窗口大小发生改变,这里做了一些处理

for(int i=10;i<size;i+=10)
{
    result.insert(i, "\n");
}

4.3双击放大

双击和单机区分部分:

重写这两部分进去区分(效果不太精准)

void mousePressEvent(QMouseEvent *event); // 鼠标按压事件
void mouseDoubleClickEvent(QMouseEvent *event); // 鼠标双击事件

放大部分和四通道切换类似,只是放大后需要把滚动条隐藏

5.视频播放

5.1倍速播放

改变sleep的时间

msleep(waitTime);

 这里下拉框绑定槽函数来改变线程的waitTime

connect(this->combobox1,SIGNAL(currentIndexChanged(int)),this,SLOT(changeSpead(int)));

void Player::changeSpead(int index)
{
    int spead = 40 - 10*index;
    th->setWaitTime(spead);
}

5.2视频暂停

点击按钮设定播放线程puase为true,循环直到状态改变

while(puase)
{
    if(end)
        break;
}

5.3视频转码

选择格式后,拼接出不同的文件名

void EncodeThreah::encodeFrame(AVFrame *pictureYUV)
{
    //把AVFrame发送给pCodecContext
    int res = avcodec_send_frame(this->pCodecContext, pictureYUV);
    if(res<0)
    {
        qDebug()<<"avcodec_send_frame error";
        return;
    }
    //一帧YUV420P压缩可能压缩成2个AVPacket
    while (res >= 0) {
        pictureYUV->pts = pkt_index++;
        //把一帧AVFrame压缩成AVPacket
        res = avcodec_receive_packet(this->pCodecContext, this->pkt);
        if(res == AVERROR_EOF || res == AVERROR(EAGAIN))
        {
            break;
        }
        //AVPacket写入h264文件
        av_interleaved_write_frame(this->opFormatContext, this->pkt);
        num++;
        //编码帧数+1
    }
}

5.4进度条拖动

这里设置进度条长度为视频帧数,拖动后发送信号,捕捉后进行判断

1.当前帧数大于目标帧数

关闭当前的播放线程,重新开启播放线程,到达目标帧数后再发送QIMage

2.当前帧数小于等于目标帧数

到达目标帧数后再发送QIMage

5.5视频切换

这里设置了一个indexnow专门后来记录播放的视频在QList中的位置,在点击按钮后,关闭当前的播放线程,设置path后重新开启播放线程

这里要注意重新设置滚动条,否则会出现频闪等现象

下面是切换上一个视频的槽函数

void VideoPlaybackWin::videoUpOne()
{
    indexnow -= 1;
    if(indexnow >= 0)
    {
        player->setEnd(true);
        player->setPath(videoList.at(indexnow).getPath());

        QString filePath = videoList.at(indexnow).getPath();
        QFileInfo fileInfo(filePath);
        QString fileName = fileInfo.fileName();
        QString extractedString = fileName.section('.', 0, 0);

        player->setTitle(extractedString);
        player->setUid(uid);
        player->setTime(videoList.at(indexnow).getTime());
        player->play();
    }
    else {
        QMessageBox::information(this,"提示","已经是第一个视频");
        return;
    }
}

6.日志查看界面

主要是使用 

QWidget *scrollWidget;
QScrollArea *scrollArea;

并且使用QHBoxLayout来达到一组信息一行的效果

QHBoxLayout *rowLayout = new QHBoxLayout();
    QList<QString> loglist = logController::getlogController()->getLog();
    for (int i = 0; i < loglist.size(); i++) {
        QLabel* labelLog = new QLabel(loglist[i]);

        // 每四个 QLabel 添加一个新的行布局
        if (i % 4 == 0) {
            rowLayout = new QHBoxLayout();
            scrollLayout->addLayout(rowLayout);
        }

        rowLayout->addWidget(labelLog);
    }

7.设置界面

7.1多选下拉框

这里是使用了一个博客封装好的部分,暂时找不到原来的链接了,找到了会在这里进行补充

7.2摄像头设备获取

获取设置好要使用的摄像头设备并判断是否可用,这里的getRead是摄像头线程进行相关的准备工作

namelist = SetController::getSetController()->cheakRow().at(3).split(";", QString::SkipEmptyParts);
int n = namelist.size();
    if(n > 0)
    {
        th1->setName(namelist.at(0));
        if(th1->getReady() != 0) 
        {
            QMessageBox::information(this,"提示","摄像头无法打开");
            logController::getlogController()->creatLog(-1,"设备故障");
            return;
        }
        logController::getlogController()->creatLog(-1,"设备正常");
        th1->start();
        connect(th1,SIGNAL(change(QImage)),this,SLOT(getImg1(QImage)));
    }
    if(n > 1)
    {
        th2->setName(namelist.at(1));
        if(th2->getReady() != 0)
        {
            QMessageBox::information(this,"提示","摄像头无法打开");
            logController::getlogController()->creatLog(-1,"设备故障");
            return;
        }
        logController::getlogController()->creatLog(-1,"设备正常");
        th2->start();
        connect(th2,SIGNAL(change(QImage)),this,SLOT(getImg2(QImage)));
    }
    if(n > 2)
    {
        th3->setName(namelist.at(2));
        if(th3->getReady() != 0)
        {
            QMessageBox::information(this,"提示","摄像头无法打开");
            logController::getlogController()->creatLog(-1,"设备故障");
            return;
        }
        logController::getlogController()->creatLog(-1,"设备正常");
        th3->start();
        connect(th3,SIGNAL(change(QImage)),this,SLOT(getImg3(QImage)));
    }
    if(n > 3)
    {
        th4->setName(namelist.at(3));
        if(th4->getReady() != 0)
        {
            QMessageBox::information(this,"提示","摄像头无法打开");
            logController::getlogController()->creatLog(-1,"设备故障");
            return;
        }
        logController::getlogController()->creatLog(-1,"设备正常");
        th4->start();
        connect(th4,SIGNAL(change(QImage)),this,SLOT(getImg4(QImage)));
    }

联系我

如果发现相关bug或者想和我讨论这个项目,可以加我的微信hell0_0123456789

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值