远程视频监控系统
项目开发流程
- 一、需求分析:明确系统的功能要求
- 二、概要设计:设计系统的整体架构和模块划分
- 三、详细设计:设计每个模块的组织结构和执行流程
- 四、编写代码:编程实现每个模块的具体功能
- 五、测试运行:测试功能,修改BUG
- 六、升级维护:优化程序,增加功能
一. 需求分析
使用UVC摄像头,实时获取视频,通过HTTP协议传输视频数据,并实时显示到WEB浏览器或者PC客户端
- 在ubuntu系统架设视频服务器(mjpg-streamer),实现抓取视频图像数据
- 利用HTTP协议实现和视频服务器的数据交互,编写客户端程序(C++),向视频服务器发送获取视频的请求,并接收响应数据
- 分析视频服务器的响应数据格式,从返回的数据中剥离出保存一帧图像,即一张JPEG格式的图片,获取的图片可以用图像查看工具直接打开
- 使用QT的网络编程框架,向视频服务器发送获取视频或截图请求,并通过QT的信号和槽机制实时接收服务返回的响应数据,从中剥离出JPEG图像帧并显示到QT界面,通过不断刷新显示JPEG图像帧的方式,实现视频监控的客户端
二. 概要设计
远程视频监控系统结构框图
三. 详细设计
1. Mjpg-streamer简介
- 网络视频服务器(Mjpg-streamer),采用多线程的工作方式,可以获取UVC摄像头的视频数据,并利用网络将视频数据发送给客户端
- Mjpg-streamer内置HTTP服务器(web server)用户可以通过浏览器直接访问服务器从而获取视频,也可以通过HTTP协议,编写Qt客户端,实现获取和显示视频流
- Mjpg-streamer采用高内聚低耦合的系统架构,将输入插件和输出插件分离,编译维护
- 输入插件只能有一个,从UVC摄像头插件(intput_uvc.so)测试图片插件(intput_testpicture.so)等选择一个,作为视频图像获取来源
- 输出插件可以是多个,如将视频流通过http输出插件(output_http.so)同时发送多个客户端,同时也可以用输出文件插件将视频数据保存起来
2. UVC摄像头简介
- UVC该驱动适用于符合USB视频类(USB Video Class)规范的摄像头设备,它包括V4L2内核设备驱动和用户空间工具补丁,大多数容量存储器设备(如U盘)都遵循USB规划,因而仅用一个单一驱动就可以操作他们。与此类似,UVC兼容外设只需一个通用驱动即可
- USB摄像头大体上可以分为UVC cameras和non-UVC cameras,UVC是一个开放的标准,拥有维护良好的驱动,它属于内核代码的一部分。插入摄像头后就可以工作,而无需编译或安装额外的驱动
3. HTTP协议简介
4. MJPG简介
- MJPG是MJPEG “Motion Joint Photogrphic Experts Group” 的缩写,即联合运动摄影专家小组,MJPEG还可以表示文件格式扩展名,是一种视频编码格式
- MJPG视频格式笨猪就是由系列JPEG图形帧组成的视频,所以MJPG每一帧数据实质就是一张JPEG格式的图片
5. JPEG图片
- JPEG文件大体上有两部分组成:标记码(TAG)和压缩数据,标记码部分分给出了JPEG图像的所有信息,如图像的宽、高、huffman表等
- 标记码由两个字节构成,其前一个字节是固定值OxFF,后一个字节则根据不同意义有不同数值,一个完整的两字节的标记码后,就是标记码对应的压缩数据流,记录了关于文件的各种信息。
6. 从视频服务器获取图像帧分析
hexdump -C /tmp/test.mjpeg |less
四. 服务端编写代码
这里不再自己编写,使用开源项目
源码地址:https://github.com/jacksonliam/mjpg-streamer.git
- 部署流程:
Ubuntu系统:
sudo wget https://github.com/jacksonliam/mjpg-streamer/archive/refs/heads/master.zip
sudo apt-get update
sudo apt-get install -y unzip
sudo unzip master.zip
cd mjpg-streamer-master/mjpg-streamer-experimental/
sudo apt-get install -y cmake libjpeg8-dev
sudo apt-get install -y gcc g++
sudo make
sudo make install
sudo cd ./plugins/input_testpicture/ &&sudo make
sudp cp ./input_testpicture.so ../../
**Centos 8 **:
yum -y update
yum -y install git gcc g++ cmake cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel
yum -y install ImageMagick
cd /opt && wget https://github.com/jacksonliam/mjpg-streamer/archive/refs/heads/master.zip
unzip master.zip
cd mjpg-streamer-master/mjpg-streamer-experimental/
make
cd ./plugins/input_testpicture/ && make
cp ./input_testpicture.so ../../
- 编译mjpg-streamer问题:
编译报错一般是Centos 7系统出现
提示缺少"jpeglib.h",解决方法安装jpeg库
sudo apt-get install libjpeg-dev
提示 /bin/sh: convert: command not found
yum -y install ImageMagick
- 修改 .start.sh脚本
使用UVC摄像头作为输入插件
./mjpg_streamer -i "./input_uvc.so -n -f 30 -r 640x480 -d /dev/video0" -o "./output_http.so -w ./www" &
使用测试图片作为输入插件
先把UVC的注释添加静态图片的库使用
./mjpg_streamer -i "./input_testpicture.so -r 320x240 -d 500" -o "./output_http.so -w ./www"
运行命令:
sudo sh start.sh &
五.测试
默认端口是8080,如果需要更改端口在脚本命令后台添加即可如:-p 8001
五. 客户端编码
QT视频监控客户端编码:
- 使用QT网络应用开发相关类QNetworkAccessMessager、QNetworkRequest、QNetworkReply管理HTTP通信过程
- 发送视频或者快照
- 接收响应数据并保存
- 从响应数据中剥离图像帧
- 在QLabel控件上显示图像帧或快照
- 重复以上过程即可看到实时视频监控画面
进入主页
1. 创建工程
参考代码:
- 工程文件:Mjpgclient.pro
- 头文件:login.h、mainwindow.h 、version.h
- 源文件:login.cpp 、mainwindow.h、version.h 、main.h
- Forms : login.ui、mainwindows.h、version.h
- Mjpgclient.pro
QT += core gui network
TRANSLATIONS = translation_ch.ts
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
login.cpp \
main.cpp \
mainwindow.cpp \
version.cpp
HEADERS += \
login.h \
mainwindow.h \
version.h
FORMS += \
login.ui \
mainwindow.ui \
version.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
DISTFILES += \
translation_ch.ts
RESOURCES += \
images.qrc \
translations.qrc
- login.h
#ifndef LOGIN_H
#define LOGIN_H
#include <QDialog>
namespace Ui {
class login;
}
class login : public QDialog
{
Q_OBJECT
public:
explicit login(QWidget *parent = nullptr);