一、主要实现功能
1、支持四路设备接入
2、实时视频分屏显示
3、接入设备信息存储
二、待完善功能(现阶段)
1、设备的删除 (已更新)
2、语音对讲 (暂时不处理)
3、视频输出通道的实时修改 (已更新)
三、运行效果
1、参数配置
2、设备显示,显示所有添加的设备以及实时显示在线状态
3、视频输出
视频输出采用的GB28181协议通过UDP接收数据,ffmpeg进行数据处理显示,后面准备添加rtsp拉流功能
因为只有一台设备,暂时只能通过修改输出通道进行测试分屏显示
//实现分屏
M_VideoWidget::M_VideoWidget(QWidget* parent)
: QWidget{ parent }
{
}
void M_VideoWidget::init()
{
#ifndef no_style
QStringList qss;
qss.append("QFrame{border:2px solid #000000;}");
qss.append("QLabel{font:75 25px;color:#F0F0F0;border:2px solid #AAAAAA;background:#303030;}");
qss.append("QLabel:focus{border:2px solid #00BB9E;background:#555555;}");
//将所有字符串接
this->setStyleSheet(qss.join(""));
#endif
//表格布局存放通道
QGridLayout* gridLayout = new QGridLayout(this);
gridLayout->setSpacing(1);
gridLayout->setContentsMargins(0, 0, 0, 0);
int height = this->height() / 2;
int width = this->width() / 2;
qDebug() << this->height() << this->width();
int m_videoNume = 4;
for (int i = 0; i < m_videoNume; ++i)
{
My_Glabel* widget = new My_Glabel(this);
widget->setFixedHeight(height - 7);
widget->setFixedWidth(width - 7);
widget->setObjectName(QString("video%1").arg(i + 1));
widget->installEventFilter(this);
widget->setFocusPolicy(Qt::StrongFocus);
// widget->setAlignment(Qt::AlignCenter);
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_widget << widget;
}
gridLayout->addWidget(m_widget.at(0), 0, 0, 1, 1);
gridLayout->addWidget(m_widget.at(1), 0, 1, 1, 1);
gridLayout->addWidget(m_widget.at(2), 1, 0, 1, 1);
gridLayout->addWidget(m_widget.at(3), 1, 1, 1, 1);
this->setLayout(gridLayout);
}
void M_VideoWidget::setheight(int height)
{
this->setFixedHeight(height);
}
void M_VideoWidget::setwidth(int width)
{
this->setFixedWidth(width);
}
void M_VideoWidget::getWidgets(QList<My_Glabel*>& widget)
{
int num = m_widget.size();
widget = m_widget;
}
int M_VideoWidget::setIamge(int num, QImage image)
{
m_widget.at(num)->setPixmap(image);
return 0;
}
//UDP接收视频数据,对数据包进行处理,接收到一定数量的udp包后再进行数据的解析
void My_UdpServer::run()
{
//ffmpeg初始化
m_peg->init();
int c;
static struct {
const char* name;
t_format format;
} formats[] = {
{"dump", F_dump},
{"header", F_header},
{"hex", F_hex},
{"rtcp", F_rtcp},
{"short", F_short},
{"payload", F_payload},
{"ascii", F_ascii}
};
t_format format = F_ascii;
struct sockaddr_in sin, rtp;
struct timeval start;
struct timeval timeout; /* timeout to limit recording */
double dstart; /* time as double */
float duration = 1000000; /* maximum duration in seconds */
int trunc = 1000000; /* bytes to show for F_hex and F_dump */
enum { FromFile, FromNetwork } source;
int sock[2];
fd_set readfds;
extern char* optarg;
extern int optind;
int i;
int nfds = 0;
extern double tdbl(struct timeval*);
startupSocket();
/* set maximum time to gather packets */
timeout.tv_sec = duration;
timeout.tv_usec = (duration - (float)timeout.tv_sec) * 1000000.0;
/* if no optional arguments, we are reading from a file */
source = FromNetwork;
char ip[] = "192.168.1.22/30004"; //为测试方便这里暂时将ip与端口固定
if (hpt(ip, &sin, NULL) == -1) {
exit(1);
}
rtp = sin;
nfds = open_network(ip, format != F_rtcp, sock, &sin);
gettimeofday(&start, 0);
dstart = tdbl(&start);
format = F_payload;
#if 1
while (1)
{
int len;
RD_buffer_t packet;
struct timeval now;
double dnow;
if (source == FromNetwork)
{
FD_ZERO(&readfds);
if (sock[0] >= 0) FD_SET(sock[0], &readfds);
if (sock[1] >= 0) FD_SET(sock[1], &readfds);
c = select(nfds + 1, &readfds, 0, 0, &timeout);
if (c < 0)
{
perror("select");
exit(1);
}
/* end of recording time reached */
else if (c == 0)
{
if (verbose)
fprintf(stderr, "Time limit reached.\n");
exit(0);
}
for (i = 0; i < 2; i++)
{
if (sock[i] >= 0 && FD_ISSET(sock[i], &readfds))
{
int alen = sizeof(sin);
/* subtract elapsed time from remaining timeout ,如果应用再linux 下需要注意以下的几个函数有所变化*/
gettimeofday(&now, 0);
dnow = tdbl(&now);
timeout.tv_sec = duration - (dnow - dstart);
if (timeout.tv_sec < 0) timeout.tv_sec = 0;
len = recvfrom(sock[i], packet.p.data, sizeof(packet.p.data),
0, (struct sockaddr*)&sin, &alen);
qDebug("----- %s",inet_ntoa(sin.sin_addr));
int channel = -1;
M_Sqlite::inst()->findChannel(inet_ntoa(sin.sin_addr), channel);
//data_Process(packet.p.data, len);
data_Process(channel,packet.p.data, len);
}
}
}
}
#endif
}