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

View File

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

View File

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

View File

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

23
Menu.ui
View File

@ -6,19 +6,20 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>300</width> <width>130</width>
<height>200</height> <height>100</height>
</rect> </rect>
</property> </property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">/*QWidget#Menu{ <string notr="true">QPushButton {
background: rgba(0, 0, 0, 0.5);
}*/
QPushButton {
border: none; border: none;
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.7);
color: #ffffff; color: #ffffff;
@ -49,12 +50,12 @@ QPushButton::checked{
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>100</height> <height>50</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>17</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="text"> <property name="text">
@ -73,12 +74,12 @@ QPushButton::checked{
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>100</height> <height>50</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>17</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="text"> <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 \ Config.cpp \
Channel.cpp \ Channel.cpp \
Menu.cpp\ Menu.cpp\
ProgressBar.cpp
HEADERS += \ HEADERS += \
Widget.h \ Widget.h \
@ -41,7 +42,12 @@ HEADERS += \
Config.h \ Config.h \
Channel.h \ Channel.h \
Menu.h \ Menu.h \
ProgressBar.h
FORMS += \ FORMS += \
Widget.ui \ Widget.ui \
Menu.ui Menu.ui \
ProgressBar.ui
RESOURCES += \
res.qrc

View File

@ -1,6 +1,15 @@
#include "TcpController.h" #include "TcpController.h"
#include "Config.h"
#include "Json.h"
#include <QDebug> #include <QDebug>
#include <QDir> #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) TcpController::TcpController(QObject* parent)
: QObject(parent) : QObject(parent)
@ -8,8 +17,11 @@ TcpController::TcpController(QObject* parent)
// map the requesr url and the handler // map the requesr url and the handler
routes.insert("set_ipaddr", std::bind(&TcpController::setIpaddr, this, std::placeholders::_1)); 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("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("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("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() Routes TcpController::getRoutes()
@ -23,6 +35,44 @@ Routes TcpController::getRoutes()
*/ */
void TcpController::setIpaddr(QTcpSocket* socket) 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) 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) void TcpController::getFileList(QTcpSocket* socket)
{ {
QDir dir("/root/usb/videos"); QVariantMap params = this->parseParams(socket);
if (!dir.exists()) { if (params.isEmpty() || !params.contains("interface")) {
qDebug() << "dictionary /root/usb/videos dont exists"; qDebug() << "getFileList params error";
socket->write("url=get_file_list\r\nstatus=error");
return; return;
} }
dir.setFilter(QDir::Files);
dir.setSorting(QDir::Name); QString interface = params.value("interface").toString();
QStringList nameFilters; QString videoPath = QString("%1/%2").arg(VideoPath).arg(interface);
nameFilters << "*.mp4";
dir.setNameFilters(nameFilters); QStringList videoList = this->listFile(videoPath);
QStringList fileList = dir.entryList();
QString data = fileList.join(","); 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()); 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 * @brief delete video file by file name
* @param socket * @param socket
*/ */
void TcpController::deleteFile(QTcpSocket* socket) void TcpController::deleteFile(QTcpSocket* socket)
{ {
QString data = socket->readLine().trimmed(); QVariantMap params = this->parseParams(socket);
QString fileName = data.split("=")[1]; 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 #ifndef TCPCONTROLLER_H
#define TCPCONTROLLER_H #define TCPCONTROLLER_H
#include <QDir>
#include <QMap> #include <QMap>
#include <QObject> #include <QObject>
#include <QTcpSocket> #include <QTcpSocket>
@ -16,14 +17,60 @@ public:
private: private:
Routes routes; Routes routes;
void setIpaddr(QTcpSocket* socket); void setIpaddr(QTcpSocket* socket);
void setName(QTcpSocket* socket);
void getName(QTcpSocket* socket);
void setVideoEnc(QTcpSocket* socket); void setVideoEnc(QTcpSocket* socket);
void getVideoEnc(QTcpSocket* socket);
void getFileList(QTcpSocket* socket); void getFileList(QTcpSocket* socket);
void downloadFile(QTcpSocket* socket);
void deleteFile(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 #endif // TCPCONTROLLER_H

View File

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

View File

@ -1,5 +1,4 @@
#include "Widget.h" #include "Widget.h"
#include "BoxController.h"
#include "Channel.h" #include "Channel.h"
#include "Config.h" #include "Config.h"
#include "TcpServer.h" #include "TcpServer.h"
@ -20,6 +19,9 @@ extern Widget::Widget(QWidget* parent)
menu = new Menu(this); menu = new Menu(this);
menu->hide(); menu->hide();
progressBar = new ProgressBar(this);
progressBar->hide();
// set window background transparent // set window background transparent
QPalette pal = palette(); QPalette pal = palette();
pal.setBrush(QPalette::Base, Qt::transparent); pal.setBrush(QPalette::Base, Qt::transparent);
@ -36,6 +38,16 @@ extern Widget::Widget(QWidget* parent)
// init command map // init command map
initCommandMap(); 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() Widget::~Widget()
@ -51,7 +63,7 @@ void Widget::initSerialPort()
{ {
// timer used to reopen serial port // timer used to reopen serial port
timer = new QTimer(); timer = new QTimer();
timer->setInterval(1000); timer->setInterval(3000);
timer->stop(); timer->stop();
// serialport // serialport
@ -78,22 +90,12 @@ void Widget::initSerialPort()
void Widget::showPlayList() void Widget::showPlayList()
{ {
// find the videos in dictionary "/root/usb/video" // find the videos in dictionary "/root/usb/video"
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curChannelName); QString dirPath = QString("%1/%2").arg(VideoPath).arg(curSelectChannel);
QDir dir(dirPath); QStringList files = this->getFileList(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();
ui->listWidget->clear(); ui->listWidget->clear();
// append fileList to qlistwidget and show // append fileList to qlistwidget and show
for (QString& file : fileList) { for (QString& file : files) {
QListWidgetItem* item = new QListWidgetItem(file); QListWidgetItem* item = new QListWidgetItem(file);
ui->listWidget->addItem(item); 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 * @brief handling error
* @param error * @param error
@ -191,35 +214,45 @@ void Widget::onReadyRead()
} }
case Forward: case Forward:
if (isPlayback) { if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName); Channel* chn = Config::findChannelByName(curSelectChannel);
chn->forward(); chn->forward();
progressBar->showMax();
} }
break; break;
case Back: case Back:
if (isPlayback) { if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName); Channel* chn = Config::findChannelByName(curSelectChannel);
chn->back(); chn->back();
progressBar->showMax();
} }
break; break;
case Pause: case Pause:
if (isPlayback) { if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName); Channel* chn = Config::findChannelByName(curSelectChannel);
chn->togglePause(); chn->togglePause();
progressBar->showMax();
if (chn->isPause) {
progressBar->setState(ProgressBar::Pause);
} else {
progressBar->setState(ProgressBar::Play);
}
} }
break; break;
case Enter: case Enter:
// if menu show, then hide menu and show play list // if menu show, then hide menu and show play list
if (menu->isVisible()) { if (menu->isVisible()) {
curChannelName = menu->getCurChannel(); curSelectChannel = menu->getCurChannel();
menu->hide(); menu->hide();
showPlayList(); showPlayList();
} else { } else {
// if list widget show, then current channel playback and other channel play live // if list widget show, then current channel playback and other channel play live
if (ui->listWidget->isVisible()) { if (ui->listWidget->isVisible()) {
if (ui->listWidget->count() == 0)
return;
QString fileName = ui->listWidget->currentItem()->text(); QString fileName = ui->listWidget->currentItem()->text();
Channel* channel = nullptr; Channel* channel = nullptr;
for (int i = 0; i < channelList.count(); i++) { for (int i = 0; i < channelList.count(); i++) {
if (channelList.at(i)->channelName == curChannelName) { if (channelList.at(i)->channelName == curSelectChannel) {
channel = channelList.at(i); channel = channelList.at(i);
} }
if (channelList.at(i)->isPlayback) { if (channelList.at(i)->isPlayback) {
@ -227,10 +260,33 @@ void Widget::onReadyRead()
} }
} }
if (channel) { if (channel) {
// play back and output hdmi
channel->startPlayback(fileName); channel->startPlayback(fileName);
isPlayback = true; 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();
}
curPlayChannel = curSelectChannel;
curFileName = fileName;
QString dirPath = QString("%1/%2").arg(VideoPath).arg(curPlayChannel);
fileList = this->getFileList(dirPath);
}
} }
ui->listWidget->hide(); // ui->listWidget->hide();
} }
} }
break; break;
@ -238,15 +294,38 @@ void Widget::onReadyRead()
if (menu->isVisible()) { if (menu->isVisible()) {
menu->hide(); menu->hide();
} }
if (ui->listWidget->isVisible()) { if (isPlayback && !ui->listWidget->isVisible()) {
ui->listWidget->hide(); Channel* chn = Config::findChannelByName(curSelectChannel);
}
if (isPlayback) {
Channel* chn = Config::findChannelByName(curChannelName);
chn->startPlayLive(); chn->startPlayLive();
progressBar->hide();
} else {
ui->listWidget->hide();
} }
break; break;
default: default:
break; 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 #define WIDG_H
#include "Menu.h" #include "Menu.h"
#include "ProgressBar.h"
#include <QDebug>
#include <QDir>
#include <QMap> #include <QMap>
#include <QSerialPort> #include <QSerialPort>
#include <QSerialPortInfo> #include <QSerialPortInfo>
@ -36,6 +39,9 @@ private slots:
void onSerialError(QSerialPort::SerialPortError error); void onSerialError(QSerialPort::SerialPortError error);
void onTimeout(); void onTimeout();
void onReadyRead(); void onReadyRead();
void onProgressTimeout();
void onPlayEnd();
void onSignalInputed(QString name, int width, int height);
private: private:
Ui::Widget* ui; Ui::Widget* ui;
@ -45,15 +51,41 @@ private:
QSerialPort* serialPort; QSerialPort* serialPort;
QMap<QString, Command> commandMap; QMap<QString, Command> commandMap;
QTimer* progressTimer;
bool isPlayback = false; bool isPlayback = false;
QString curChannelName; QString curPlayChannel;
QString curSelectChannel;
QString curFileName; QString curFileName;
Menu* menu; Menu* menu;
ProgressBar* progressBar;
private: private:
void initSerialPort(); void initSerialPort();
void initCommandMap(); 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 #endif // WIDG_H

View File

@ -22,6 +22,9 @@
<string notr="true"/> <string notr="true"/>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -63,14 +66,14 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>20</pointsize> <pointsize>14</pointsize>
</font> </font>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QListWidget { <string notr="true">QListWidget {
color: rgba(255, 255, 255); color: rgba(255, 255, 255);
outline: none; outline: none;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.4);
border: none; border: none;
} }
@ -81,7 +84,7 @@
} }
#listWidget::item:selected { #listWidget::item:selected {
background-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.5);
border-left: 10px solid 00AEEC; border-left: 10px solid 00AEEC;
color: #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 "Config.h"
#include "Link.h" #include "Link.h"
#include "TcpServer.h" #include "TcpServer.h"
@ -11,20 +10,24 @@
TcpServer* server; TcpServer* server;
LinkObject* vo; LinkObject* vo;
LinkObject* vo1; 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[]) int main(int argc, char* argv[])
{ {
// init Link
if (!Link::init()) { if (!Link::init()) {
qDebug() << "Link init failed!"; qDebug() << "Link init failed, exit!";
return 0; return 0;
} }
// init videooOutput and linuxfb before init QApplication, // init videooOutput and linuxfb before init QApplication,
// otherwise dump because cant init screen and we have ui components // 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"); vo = Link::create("OutputVo");
QVariantMap dataVo; QVariantMap dataVo;
dataVo["vid"] = 0; dataVo["vid"] = 0;
@ -69,8 +72,9 @@ int main(int argc, char* argv[])
Config::loadConfig(ConfigurationPath); Config::loadConfig(ConfigurationPath);
// create server and listen port 8080 // create server and listen port 8080
// server = new TcpServer(); server = new TcpServer();
// server->listen(QHostAddress::Any, 8080); server->listen(QHostAddress::Any, 8080);
qDebug() << "start tcp server, listen port 8080...";
Widget w; Widget w;
w.show(); 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>