Modify the project from one channel to two channels

This commit is contained in:
zc 2024-01-24 17:57:08 -08:00
parent c929823364
commit e8222a87ef
21 changed files with 789 additions and 120 deletions

View File

@ -11,9 +11,8 @@ LinkObject* Channel::videoDecoder = nullptr;
extern LinkObject* vo;
extern LinkObject* vo1;
const char* VideoPath = "/root/usb/videos";
const char* SnapPath = "/root/usb/snap";
extern const char* VideoPath;
extern const char* SnapPath;
Channel::Channel(QObject* parent)
: QObject(parent)
@ -35,7 +34,7 @@ Channel::Channel(QObject* parent)
audioInput = Link::create("InputAlsa");
QVariantMap dataIn;
dataIn["path"] = "hw:0,0";
dataIn["channels"] = 2;
audioInput->start(dataIn);
}
if (audioOutput == nullptr) {
@ -50,11 +49,11 @@ Channel::Channel(QObject* parent)
}
if (file == nullptr) {
file = Link::create("InputFile");
// one video playback end
connect(file, &LinkObject::newEvent, [=](QString type, QVariant) {
if (type == "EOF") {
qDebug() << "one video playback end";
emit playEnd();
}
});
}
@ -91,7 +90,20 @@ void Channel::init()
videoInput = Link::create("InputVi");
QVariantMap dataVi;
dataVi["interface"] = channelName;
dataVi["width"] = 1280;
dataVi["height"] = 1024;
videoInput->start(dataVi);
connect(videoInput, &LinkObject::newEvent, [=](QString type, QVariant msg) {
if (type == "signal") {
QVariantMap data = msg.toMap();
bool avalible = data["avalible"].toBool();
if (avalible) {
int width = data["width"].toInt();
int height = data["height"].toInt();
emit signalInputed(channelName, width, height);
}
}
});
// start water mask
// overLay->start();
@ -202,11 +214,24 @@ void Channel::startPlayback(QString fileName)
QVariantMap dataFile;
dataFile["path"] = path;
dataFile["async"] = false;
file->start(dataFile);
isPlayback = true;
}
/**
* @brief get video duration of current channel
* @param fileName
* @return
*/
int Channel::getDuration(QString fileName)
{
QString path = QString("%1/%2/%3").arg(VideoPath).arg(channelName).arg(fileName);
int duration = file->invoke("getDuration", path).toInt();
return duration;
}
/**
* @brief play live
*/
@ -224,9 +249,9 @@ void Channel::startPlayLive()
*/
void Channel::back()
{
qDebug() << "back 10s";
qDebug() << channelName << "back 10s";
int curPos = file->invoke("getPosition").toInt();
curPos -= 10 * 100;
curPos -= 10 * 1000;
file->invoke("seek", curPos);
}
@ -235,9 +260,9 @@ void Channel::back()
*/
void Channel::forward()
{
qDebug() << "forward 10s";
qDebug() << channelName << "forward 10s";
int curPos = file->invoke("getPosition").toInt();
curPos += 10 * 100;
curPos += 10 * 1000;
file->invoke("seek", curPos);
}

View File

@ -24,6 +24,7 @@ public:
QVariantMap audioEncoderParams;
LinkObject* record;
bool autoRecord = false;
// 1 hour each video
int duration = 1 * 60 * 1000;
bool isRecord = false;
@ -50,9 +51,12 @@ public:
void back();
void forward();
void togglePause();
int getDuration(QString fileName);
void startPlayLive();
signals:
void playEnd();
void signalInputed(QString name, int width, int height);
private slots:
void onTimeout();

View File

@ -5,21 +5,26 @@
#include <QFileInfo>
#include <QList>
// input channels list
QList<Channel*> channelList;
Config::Config()
{
}
void Config::loadConfig(QString path)
/**
* @brief load config when initialize
* @param path
*/
void Config::loadConfig(QString configPath)
{
QFileInfo fileInfo(path);
QFileInfo fileInfo(configPath);
if (!fileInfo.exists()) {
qDebug() << "config.json does not exist, exit";
exit(0);
}
// read the configuration
QVariantMap config = Json::loadFile(path).toMap();
QVariantMap config = Json::loadFile(configPath).toMap();
QVariantList list = config["interface"].toList();
for (int i = 0; i < list.count(); i++) {
Channel* chn = new Channel();
@ -37,10 +42,16 @@ void Config::loadConfig(QString path)
bool autoRecord = cfg["autoRecord"].toBool();
if (autoRecord) {
// chn->startRecord();
chn->autoRecord = autoRecord;
}
channelList.push_back(chn);
}
for (Channel* chn : channelList) {
if (chn->autoRecord) {
chn->startRecord();
}
}
}
/**

View File

@ -7,11 +7,13 @@
class Config {
public:
Config();
static void loadConfig(QString path);
static void loadConfig(QString configPath);
static void upadteConfig(QString cfg);
static Channel* findChannelByName(QString name);
private:
void initConfig();
static QString path;
};
#endif // CONFIG_H

23
Menu.ui
View File

@ -6,19 +6,20 @@
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>200</height>
<width>130</width>
<height>100</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">/*QWidget#Menu{
background: rgba(0, 0, 0, 0.5);
}*/
QPushButton {
<string notr="true">QPushButton {
border: none;
background: rgba(0, 0, 0, 0.7);
color: #ffffff;
@ -49,12 +50,12 @@ QPushButton::checked{
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<pointsize>17</pointsize>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
@ -73,12 +74,12 @@ QPushButton::checked{
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<pointsize>17</pointsize>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">

120
ProgressBar.cpp Normal file
View File

@ -0,0 +1,120 @@
#include "ProgressBar.h"
#include "ui_ProgressBar.h"
#include <QDebug>
#define DURATION 10000
ProgressBar::ProgressBar(QWidget* parent)
: QWidget(parent)
, ui(new Ui::ProgressBar)
{
ui->setupUi(this);
// move to bottom of screen
this->setFixedWidth(parent->width());
int height = parent->height();
this->move(0, height - this->height());
timer = new QTimer();
timer->setInterval(DURATION);
timer->stop();
connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
QString styles = "QSlider::groove:horizontal { \
border: none; \
height: 6px; \
border-radius: 3px; \
background: #FF5C38; \
} \
QSlider::sub-page:horizontal { \
background: #FF5C38; \
height: 4px; \
border-radius: 3px; \
} \
QSlider::add-page:horizontal { \
background: #949494; \
height: 4px; \
border-radius: 3px; \
}";
QString max = "QSlider::handle:horizontal {\
border: none;\
margin: -5px 0px;\
width: 16px;\
height: 16px;\
border-radius: 8px;\
background: #FF5C38;\
}";
QString min = "QSlider::handle:horizontal {\
border: none;\
margin: -5px -8px;\
width: 16px;\
height: 16px;\
border-radius: 8px;\
background: rgba(0, 0, 0, 0);\
}";
sliderMaxStyles = styles + max;
sliderMinStyles = styles + min;
this->setStyleSheet(sliderMaxStyles);
}
ProgressBar::~ProgressBar()
{
delete ui;
delete timer;
}
void ProgressBar::setDuration(int dur)
{
this->duration = dur;
ui->horizontalSlider->setMaximum(dur);
QString time = this->secToString(dur);
this->durationStr = time;
ui->label->setText(QString("00:00:00/%1").arg(time));
}
void ProgressBar::setCurrent(int cur)
{
ui->horizontalSlider->setValue(cur);
QString time = this->secToString(cur);
ui->label->setText(QString("%1/%2").arg(time).arg(durationStr));
}
void ProgressBar::showMax()
{
if (timer->isActive()) {
timer->stop();
timer->start();
} else {
timer->start();
}
if (!isMax) {
this->setFixedHeight(100);
ui->horizontalSlider->setStyleSheet(sliderMaxStyles);
this->move(0, parentWidget()->height() - this->height());
ui->widget->setStyleSheet("QWidget#widget{background-color: rgba(0, 0, 0, 0.7);}");
isMax = true;
ui->actionContainer->show();
}
}
void ProgressBar::onTimeout()
{
ui->actionContainer->hide();
ui->horizontalSlider->setStyleSheet(sliderMinStyles);
this->setFixedHeight(ui->horizontalSlider->height() + ui->widget->layout()->contentsMargins().top());
this->move(0, parentWidget()->height() - this->height());
ui->widget->setStyleSheet("QWidget#widget{background-color: rgba(0, 0, 0, 0);}");
timer->stop();
isMax = false;
}
void ProgressBar::setState(PlayState state)
{
if (state == Play) {
ui->lblStatus->setPixmap(QPixmap(":/images/pause.png"));
} else {
ui->lblStatus->setPixmap(QPixmap(":/images/start.png"));
}
}

49
ProgressBar.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
#include <QTime>
#include <QTimer>
#include <QWidget>
namespace Ui {
class ProgressBar;
}
class ProgressBar : public QWidget {
Q_OBJECT
public:
enum PlayState {
Play,
Pause
};
explicit ProgressBar(QWidget* parent = 0);
~ProgressBar();
void showMax();
void setDuration(int dur);
void setCurrent(int cur);
void setState(PlayState state);
inline QString secToString(int msc);
private slots:
void onTimeout();
private:
Ui::ProgressBar* ui;
int duration;
QString durationStr;
QTimer* timer;
bool isMax = true;
QString sliderMaxStyles;
QString sliderMinStyles;
};
inline QString ProgressBar::secToString(int msc)
{
QString formatStr = QTime(0, 0, 0).addSecs(msc).toString(QString::fromUtf8("hh:mm:ss"));
return formatStr;
}
#endif // PROGRESSBAR_H

138
ProgressBar.ui Normal file
View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProgressBar</class>
<widget class="QWidget" name="ProgressBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>776</width>
<height>100</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="styleSheet">
<string notr="true">QWidget#widget {
background-color: rgba(0, 0, 0, 0.7);
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>30</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSlider" name="horizontalSlider">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="actionContainer" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lblStatus">
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>:/images/begin.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QLabel {
color: #ffffff;
}</string>
</property>
<property name="text">
<string>00:00:00/00:00:00</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -33,6 +33,7 @@ SOURCES += \
Config.cpp \
Channel.cpp \
Menu.cpp\
ProgressBar.cpp
HEADERS += \
Widget.h \
@ -41,7 +42,12 @@ HEADERS += \
Config.h \
Channel.h \
Menu.h \
ProgressBar.h
FORMS += \
Widget.ui \
Menu.ui
Menu.ui \
ProgressBar.ui
RESOURCES += \
res.qrc

View File

@ -1,6 +1,15 @@
#include "TcpController.h"
#include "Config.h"
#include "Json.h"
#include <QDebug>
#include <QDir>
#include <QProcess>
extern const char* VideoPath;
extern const char* SnapPath;
extern const char* NetConfigPath;
extern const char* NetScriptPath;
extern const char* ConfigurationPath;
TcpController::TcpController(QObject* parent)
: QObject(parent)
@ -8,8 +17,11 @@ TcpController::TcpController(QObject* parent)
// map the requesr url and the handler
routes.insert("set_ipaddr", std::bind(&TcpController::setIpaddr, this, std::placeholders::_1));
routes.insert("set_video_enc", std::bind(&TcpController::setVideoEnc, this, std::placeholders::_1));
routes.insert("get_video_enc", std::bind(&TcpController::getVideoEnc, this, std::placeholders::_1));
routes.insert("get_file_list", std::bind(&TcpController::getFileList, this, std::placeholders::_1));
routes.insert("delete_file", std::bind(&TcpController::deleteFile, this, std::placeholders::_1));
routes.insert("set_name", std::bind(&TcpController::setName, this, std::placeholders::_1));
routes.insert("get_name", std::bind(&TcpController::getName, this, std::placeholders::_1));
}
Routes TcpController::getRoutes()
@ -23,6 +35,44 @@ Routes TcpController::getRoutes()
*/
void TcpController::setIpaddr(QTcpSocket* socket)
{
QVariantMap params = this->parseParams(socket);
QVariantMap netMap = Json::loadFile(NetConfigPath).toMap();
if (params.contains("ip"))
netMap["ip"] = params.value("ip");
if (params.contains("mask"))
netMap["mask"] = params.value("mask");
if (params.contains("gateway"))
netMap["gateway"] = params.value("gateway");
Json::saveFile(netMap, NetConfigPath);
socket->write("url=set_ipaddr\r\nstatus=success");
writeCom(NetScriptPath);
}
/**
* @brief set box's name
* @param socket
*/
void TcpController::setName(QTcpSocket* socket)
{
QVariantMap params = this->parseParams(socket);
if (params.isEmpty() || !params.contains("name")) {
socket->write("url=set_name\r\nstatus=error");
return;
}
QVariantMap cfg = Json::loadFile(ConfigurationPath).toMap();
cfg["name"] = params.value("name");
Json::saveFile(cfg, ConfigurationPath);
socket->write("url=set_name\r\nstatus=success");
}
void TcpController::getName(QTcpSocket* socket)
{
QVariantMap config = Json::loadFile(ConfigurationPath).toMap();
QString name = config["name"].toString();
QString data = QString("url=get_name\r\nstatus=success\r\nname=%1").arg(name);
socket->write(data.toStdString().data());
}
/**
@ -31,6 +81,75 @@ void TcpController::setIpaddr(QTcpSocket* socket)
*/
void TcpController::setVideoEnc(QTcpSocket* socket)
{
QVariantMap params = this->parseParams(socket);
if (params.isEmpty() || !params.contains("interface")) {
qDebug() << "set video encode params error";
socket->write("url=set_video_enc\r\nstatus=error");
return;
}
// change resolution and framerate of channel
QString interface = params.value("interface").toString();
Channel* chn = Config::findChannelByName(interface);
if (chn)
chn->videoEncoder->setData(params);
// update config
QVariantMap cfg = Json::loadFile(ConfigurationPath).toMap();
QVariantList interfaces = cfg.value("interface").toList();
for (int i = 0; i < interfaces.length(); i++) {
QVariantMap item = interfaces.at(i).toMap();
if (item.value("name").toString() == interface) {
QVariantMap encV = item.value("encV").toMap();
if (params.contains("width"))
encV["width"] = params.value("width");
if (params.contains("height"))
encV["height"] = params.value("height");
if (params.contains("framerate"))
encV["framerate"] = params.value("framerate");
item["encV"] = encV;
interfaces.replace(i, item);
}
}
cfg["interface"] = interfaces;
Json::saveFile(cfg, ConfigurationPath);
socket->write("url=set_video_enc\r\nstatus=success");
}
void TcpController::getVideoEnc(QTcpSocket* socket)
{
QVariantMap params = this->parseParams(socket);
if (params.contains("interface")) {
QString interface = params.value("interface").toString();
QVariantMap cfg = Json::loadFile(ConfigurationPath).toMap();
QVariantList interfaces = cfg.value("interface").toList();
QVariantMap targetInterfaceCfg;
for (int i = 0; i < interfaces.length(); i++) {
QVariantMap item = interfaces.at(i).toMap();
if (item.value("name").toString() == interface) {
targetInterfaceCfg = item;
}
}
QString width;
QString height;
QString framerate;
QVariantMap encodeV = targetInterfaceCfg.value("encV").toMap();
width = encodeV.value("width").toString();
height = encodeV.value("height").toString();
framerate = encodeV.value("framerate").toString();
QString data = QString("url=get_video_enc\r\nstatus=success\r\nwidth=%1\r\nheight=%2\r\nframerate=%3")
.arg(width)
.arg(height)
.arg(framerate);
socket->write(data.toStdString().data());
} else {
qDebug() << "get video encode params error";
socket->write("url=get_video_enc\r\nstatus=error");
return;
}
}
/**
@ -39,59 +158,74 @@ void TcpController::setVideoEnc(QTcpSocket* socket)
*/
void TcpController::getFileList(QTcpSocket* socket)
{
QDir dir("/root/usb/videos");
if (!dir.exists()) {
qDebug() << "dictionary /root/usb/videos dont exists";
QVariantMap params = this->parseParams(socket);
if (params.isEmpty() || !params.contains("interface")) {
qDebug() << "getFileList params error";
socket->write("url=get_file_list\r\nstatus=error");
return;
}
dir.setFilter(QDir::Files);
dir.setSorting(QDir::Name);
QStringList nameFilters;
nameFilters << "*.mp4";
dir.setNameFilters(nameFilters);
QStringList fileList = dir.entryList();
QString data = fileList.join(",");
QString interface = params.value("interface").toString();
QString videoPath = QString("%1/%2").arg(VideoPath).arg(interface);
QStringList videoList = this->listFile(videoPath);
if (videoList.isEmpty()) {
qDebug() << "error, video folders is empty ";
socket->write("url=get_file_list\r\nstatus=error");
return;
}
QString data;
data = "url=get_file_list\r\nstatus=success\r\n" + videoList.join("\r\n");
socket->write(data.toStdString().data());
}
/**
* @brief download video file
* @param socket
*/
void TcpController::downloadFile(QTcpSocket* socket)
{
QString url = socket->readLine().trimmed();
QString fileName = url.split("=")[1];
fileName = "/root/usb/videos/" + fileName;
qDebug() << fileName;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "read file failed";
return;
}
int64_t sendSize = 0;
int64_t fileSize = file.size();
socket->write(QString("fileSize=%1\r\n").arg(fileSize).toStdString().data());
// loop reading and sending file, 15k bytes once
while (sendSize < fileSize) {
char buf[1024 * 15] = { 0 };
int len = file.read(buf, sizeof(buf));
len = socket->write(buf, len);
sendSize += len;
}
qDebug() << "send file to " << socket << "end!";
file.close();
}
/**
* @brief delete video file by file name
* @param socket
*/
void TcpController::deleteFile(QTcpSocket* socket)
{
QString data = socket->readLine().trimmed();
QString fileName = data.split("=")[1];
QVariantMap params = this->parseParams(socket);
if (params.isEmpty()) {
socket->write("url=delete_file\r\nstatus=error");
return;
}
QString interface = params.value("interface").toString();
QString fileName = params.value("fileName").toString();
// xxx.mp4 ==> xxx.jpg
QString snapName = fileName.split(".")[0] + ".jpg";
QString filePath = QString("%1/%2/%3").arg(VideoPath).arg(interface).arg(fileName);
QString snapPath = QString("%1/%2/%3").arg(SnapPath).arg(interface).arg(fileName);
QFile video(filePath);
if (video.exists()) {
video.remove();
qDebug() << "remove video:" << filePath;
QFile image(snapPath);
if (image.exists()) {
image.remove();
qDebug() << "remove image:" << snapPath;
}
socket->write("url=delete_file\r\nstatus=success");
} else {
qDebug() << "error, file:" << filePath << "do not exist";
socket->write("url=delete_file\r\nstatus=error");
}
}
QString TcpController::writeCom(const QString& com)
{
QProcess proc;
QStringList argList;
argList << "-c" << com;
proc.start("/bin/sh", argList);
// wait process start
proc.waitForFinished();
proc.waitForReadyRead();
// read data from console
QByteArray procOutput = proc.readAll();
proc.close();
return QString(procOutput);
}

View File

@ -1,6 +1,7 @@
#ifndef TCPCONTROLLER_H
#define TCPCONTROLLER_H
#include <QDir>
#include <QMap>
#include <QObject>
#include <QTcpSocket>
@ -16,14 +17,60 @@ public:
private:
Routes routes;
void setIpaddr(QTcpSocket* socket);
void setName(QTcpSocket* socket);
void getName(QTcpSocket* socket);
void setVideoEnc(QTcpSocket* socket);
void getVideoEnc(QTcpSocket* socket);
void getFileList(QTcpSocket* socket);
void downloadFile(QTcpSocket* socket);
void deleteFile(QTcpSocket* socket);
void playLive(QTcpSocket* socket);
void playFile(QTcpSocket* socket);
static QString writeCom(const QString& com);
inline QVariantMap parseParams(QTcpSocket* socket);
inline QList<QString> listFile(QString path);
};
/**
* @brief parse tcp request params
* @param socket
* @return
*/
inline QVariantMap TcpController::parseParams(QTcpSocket* socket)
{
QVariantMap params;
// exmaple:data1=xxx\r\ndata2=xxx\r\n...
QStringList data = QString(socket->readAll()).split("\r\n");
for (int i = 0; i < data.length(); i++) {
if (data.at(i).contains("=")) {
QStringList pair = data.at(i).split("=");
params.insert(pair[0], pair[1]);
}
}
return params;
}
/**
* @brief list all .mp4 file in the folder
* @param path
* @return
*/
inline QList<QString> TcpController::listFile(QString path)
{
QStringList fileList;
QDir dir(path);
if (!dir.exists()) {
qDebug() << "folder " << path << " dont exists";
return fileList;
}
dir.setFilter(QDir::Files);
dir.setSorting(QDir::Name);
QStringList nameFilters;
nameFilters << "*.mp4"
<< "*.jpg";
dir.setNameFilters(nameFilters);
fileList = dir.entryList();
return fileList;
}
#endif // TCPCONTROLLER_H

View File

@ -19,7 +19,7 @@ void TcpServer::onNewConnect()
connect(socket, &QTcpSocket::readyRead, this, &TcpServer::onReadyRead);
connect(socket, &QTcpSocket::disconnected, [=] {
QTcpSocket* sk = static_cast<QTcpSocket*>(sender());
qDebug() << "clients " << sk << "disconnected";
qDebug() << "client " << sk << "disconnected";
clients.removeOne(sk);
});
}
@ -31,12 +31,16 @@ void TcpServer::onNewConnect()
void TcpServer::onReadyRead()
{
QTcpSocket* socket = static_cast<QTcpSocket*>(sender());
QString url = socket->readLine().trimmed();
// url=xxx
QString data = socket->readLine().trimmed();
if (data.contains("=")) {
QString url = data.split("=")[1];
bool contains = controller->getRoutes().contains(url);
if (contains) {
auto handler = controller->getRoutes().value(url);
handler(socket);
} else {
socket->write("error: request url not found");
socket->write(QString("url=%1\r\nstatus=error").arg(url).toStdString().data());
}
}
}

View File

@ -1,5 +1,4 @@
#include "Widget.h"
#include "BoxController.h"
#include "Channel.h"
#include "Config.h"
#include "TcpServer.h"
@ -20,6 +19,9 @@ extern Widget::Widget(QWidget* parent)
menu = new Menu(this);
menu->hide();
progressBar = new ProgressBar(this);
progressBar->hide();
// set window background transparent
QPalette pal = palette();
pal.setBrush(QPalette::Base, Qt::transparent);
@ -36,6 +38,16 @@ extern Widget::Widget(QWidget* parent)
// init command map
initCommandMap();
// get playback position each 0.5s
progressTimer = new QTimer();
progressTimer->setInterval(500);
connect(progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimeout()));
for (Channel* chn : channelList) {
connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd()));
connect(chn, SIGNAL(signalInputed(QString, int, int)), this, SLOT(onSignalInputed(QString, int, int)));
}
}
Widget::~Widget()
@ -51,7 +63,7 @@ void Widget::initSerialPort()
{
// timer used to reopen serial port
timer = new QTimer();
timer->setInterval(1000);
timer->setInterval(3000);
timer->stop();
// serialport
@ -78,22 +90,12 @@ void Widget::initSerialPort()
void Widget::showPlayList()
{
// find the videos in dictionary "/root/usb/video"
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curChannelName);
QDir dir(dirPath);
if (!dir.exists()) {
qDebug() << "dictionary /root/usb/videos dont exists";
return;
}
dir.setFilter(QDir::Files);
dir.setSorting(QDir::Name);
QStringList nameFilters;
nameFilters << "*.mp4";
dir.setNameFilters(nameFilters);
fileList = dir.entryList();
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curSelectChannel);
QStringList files = this->getFileList(dirPath);
ui->listWidget->clear();
// append fileList to qlistwidget and show
for (QString& file : fileList) {
for (QString& file : files) {
QListWidgetItem* item = new QListWidgetItem(file);
ui->listWidget->addItem(item);
}
@ -117,6 +119,27 @@ void Widget::onTimeout()
}
}
void Widget::onProgressTimeout()
{
Channel* chn = Config::findChannelByName(curSelectChannel);
int pos = chn->file->invoke("getPosition").toInt() / 1000;
progressBar->setCurrent(pos);
}
/**
* @brief call it when input hdmi signal
* @param name
* @param width
* @param height
*/
void Widget::onSignalInputed(QString name, int width, int height)
{
if (name == "HDMI-A") {
this->setFixedSize(QSize(width, height));
qDebug() << QString("set windows size: %1x%2").arg(width).arg(height);
}
}
/**
* @brief handling error
* @param error
@ -191,35 +214,45 @@ void Widget::onReadyRead()
}
case Forward:
if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName);
Channel* chn = Config::findChannelByName(curSelectChannel);
chn->forward();
progressBar->showMax();
}
break;
case Back:
if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName);
Channel* chn = Config::findChannelByName(curSelectChannel);
chn->back();
progressBar->showMax();
}
break;
case Pause:
if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName);
Channel* chn = Config::findChannelByName(curSelectChannel);
chn->togglePause();
progressBar->showMax();
if (chn->isPause) {
progressBar->setState(ProgressBar::Pause);
} else {
progressBar->setState(ProgressBar::Play);
}
}
break;
case Enter:
// if menu show, then hide menu and show play list
if (menu->isVisible()) {
curChannelName = menu->getCurChannel();
curSelectChannel = menu->getCurChannel();
menu->hide();
showPlayList();
} else {
// if list widget show, then current channel playback and other channel play live
if (ui->listWidget->isVisible()) {
if (ui->listWidget->count() == 0)
return;
QString fileName = ui->listWidget->currentItem()->text();
Channel* channel = nullptr;
for (int i = 0; i < channelList.count(); i++) {
if (channelList.at(i)->channelName == curChannelName) {
if (channelList.at(i)->channelName == curSelectChannel) {
channel = channelList.at(i);
}
if (channelList.at(i)->isPlayback) {
@ -227,10 +260,33 @@ void Widget::onReadyRead()
}
}
if (channel) {
// play back and output hdmi
channel->startPlayback(fileName);
isPlayback = true;
// only show progressbar in HDMI-A(HDMI-OUT0)
if (channel->channelName == "HDMI-A") {
// show progress bar maximize
int duration = channel->getDuration(fileName) / 1000;
progressBar->setDuration(duration);
progressBar->setCurrent(0);
progressBar->show();
progressBar->showMax();
progressBar->setState(ProgressBar::Play);
// if timer is active, then restart timer
if (progressTimer->isActive()) {
progressTimer->stop();
progressTimer->start();
} else {
progressTimer->start();
}
ui->listWidget->hide();
curPlayChannel = curSelectChannel;
curFileName = fileName;
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curPlayChannel);
fileList = this->getFileList(dirPath);
}
}
// ui->listWidget->hide();
}
}
break;
@ -238,15 +294,38 @@ void Widget::onReadyRead()
if (menu->isVisible()) {
menu->hide();
}
if (ui->listWidget->isVisible()) {
ui->listWidget->hide();
}
if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName);
if (isPlayback && !ui->listWidget->isVisible()) {
Channel* chn = Config::findChannelByName(curSelectChannel);
chn->startPlayLive();
progressBar->hide();
} else {
ui->listWidget->hide();
}
break;
default:
break;
}
}
/**
* @brief current play end and then play next video
*/
void Widget::onPlayEnd()
{
int index = fileList.indexOf(curFileName);
// cur video is last one of list, then refresh list
if (index == fileList.length() - 1) {
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curPlayChannel);
this->getFileList(dirPath);
if (index == fileList.length() - 1) {
qDebug() << "no file to play";
return;
}
qDebug() << "refresh current play file list";
}
curFileName = fileList.at(index + 1);
Channel* chn = Config::findChannelByName(curPlayChannel);
if (chn)
chn->startPlayback(curFileName);
}

View File

@ -2,6 +2,9 @@
#define WIDG_H
#include "Menu.h"
#include "ProgressBar.h"
#include <QDebug>
#include <QDir>
#include <QMap>
#include <QSerialPort>
#include <QSerialPortInfo>
@ -36,6 +39,9 @@ private slots:
void onSerialError(QSerialPort::SerialPortError error);
void onTimeout();
void onReadyRead();
void onProgressTimeout();
void onPlayEnd();
void onSignalInputed(QString name, int width, int height);
private:
Ui::Widget* ui;
@ -45,15 +51,41 @@ private:
QSerialPort* serialPort;
QMap<QString, Command> commandMap;
QTimer* progressTimer;
bool isPlayback = false;
QString curChannelName;
QString curPlayChannel;
QString curSelectChannel;
QString curFileName;
Menu* menu;
ProgressBar* progressBar;
private:
void initSerialPort();
void initCommandMap();
inline QStringList getFileList(QString dirPath);
};
/**
* @brief get all files of cur channel
* @param path
* @return
*/
inline QStringList Widget::getFileList(QString dirPath)
{
QStringList fileList;
QDir dir(dirPath);
if (!dir.exists()) {
qDebug() << dirPath << "do not exist";
return fileList;
}
dir.setFilter(QDir::Files);
dir.setSorting(QDir::Name);
QStringList nameFilters;
nameFilters << "*.mp4";
dir.setNameFilters(nameFilters);
fileList = dir.entryList();
return fileList;
}
#endif // WIDG_H

View File

@ -22,6 +22,9 @@
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -63,14 +66,14 @@
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
<pointsize>14</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">QListWidget {
color: rgba(255, 255, 255);
outline: none;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgba(0, 0, 0, 0.4);
border: none;
}
@ -81,7 +84,7 @@
}
#listWidget::item:selected {
background-color: rgba(0, 0, 0, 0.7);
background-color: rgba(0, 0, 0, 0.5);
border-left: 10px solid 00AEEC;
color: #00AEEC;
}

BIN
images/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

1
images/pause.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1705886602595" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2210" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M209.645253 863.934444l201.049992 0 0-703.866842L209.645253 160.067602 209.645253 863.934444zM611.804588 863.934444l201.113437 0 0-703.866842L611.804588 160.067602 611.804588 863.934444z" p-id="2211" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 559 B

BIN
images/start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

1
images/start.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1705886627361" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2496" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M256.079818 160.365384 256.079818 863.633592 808.649815 511.983627Z" p-id="2497" fill="#ffffff" ></path></svg>

After

Width:  |  Height:  |  Size: 442 B

View File

@ -1,4 +1,3 @@
#include "BoxController.h"
#include "Config.h"
#include "Link.h"
#include "TcpServer.h"
@ -11,20 +10,24 @@
TcpServer* server;
LinkObject* vo;
LinkObject* vo1;
const char* ConfigurationPath = "/opt/RecordControlApplication/bin/config.json";
const char* ConfigurationPath = "/opt/RecordControlApplication/configuration/config.json";
const char* NetConfigPath = "/opt/RecordControlApplication/configuration/net.json";
const char* NetScriptPath = "/opt/RecordControlApplication/scripts/setNetwork.sh";
const char* VideoPath = "/root/usb/videos";
const char* SnapPath = "/root/usb/snap";
int main(int argc, char* argv[])
{
// init Link
if (!Link::init()) {
qDebug() << "Link init failed!";
qDebug() << "Link init failed, exit!";
return 0;
}
// init videooOutput and linuxfb before init QApplication,
// otherwise dump because cant init screen and we have ui components
// video output in channel HDMI-OUT0
// video output in channel HDMI-OUT0, only show ui in HDMI-OUT0
vo = Link::create("OutputVo");
QVariantMap dataVo;
dataVo["vid"] = 0;
@ -69,8 +72,9 @@ int main(int argc, char* argv[])
Config::loadConfig(ConfigurationPath);
// create server and listen port 8080
// server = new TcpServer();
// server->listen(QHostAddress::Any, 8080);
server = new TcpServer();
server->listen(QHostAddress::Any, 8080);
qDebug() << "start tcp server, listen port 8080...";
Widget w;
w.show();

8
res.qrc Normal file
View File

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/">
<file>images/start.svg</file>
<file>images/pause.svg</file>
<file>images/start.png</file>
<file>images/pause.png</file>
</qresource>
</RCC>