优化录制功能以及网络通信接口

This commit is contained in:
zc 2024-08-22 00:29:39 -07:00
parent d1d8655645
commit 97f22cf302
18 changed files with 285 additions and 301 deletions

View File

@ -5,17 +5,22 @@
#include "Log.h" #include "Log.h"
#include "Tool.h" #include "Tool.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QElapsedTimer>
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QTime> #include <QTime>
#include <chrono> #include <chrono>
#include <QElapsedTimer>
LinkObject* Channel::lineIn = nullptr; LinkObject* Channel::lineIn = nullptr;
LinkObject* Channel::lineOut = nullptr; LinkObject* Channel::lineOut = nullptr;
LinkObject* Channel::rtspServer = nullptr; LinkObject* Channel::rtspServer = nullptr;
LinkObject* Channel::resample = nullptr; LinkObject* Channel::resample = nullptr;
LinkObject* Channel::gain = nullptr;
LinkObject* Channel::volume = nullptr;
// 这里设置最大12dB增益最小30dB增益(超过12dB会爆音)
int Channel::maxGian = 12;
int Channel::minGain = -30;
int Channel::curGain = 0;
extern LinkObject* vo; extern LinkObject* vo;
extern LinkObject* vo1; extern LinkObject* vo1;
@ -52,15 +57,29 @@ Channel::Channel(QObject* parent)
if (lineOut == nullptr) { if (lineOut == nullptr) {
lineOut = Link::create("OutputAlsa"); lineOut = Link::create("OutputAlsa");
QVariantMap dataOut; QVariantMap dataOut;
dataOut["path"] = "hw:0,0"; dataOut["path"] = "hw:0";
lineOut->start(dataOut); lineOut->start(dataOut);
} }
if (gain == nullptr) {
gain = Link::create("Gain");
gain->start();
}
if (volume == nullptr) {
volume = Link::create("Volume");
volume->start();
gain->linkA(volume);
gain->linkA(lineOut);
}
if (rtspServer == nullptr) { if (rtspServer == nullptr) {
rtspServer = Link::create("Rtsp"); rtspServer = Link::create("Rtsp");
rtspServer->start(); rtspServer->start();
} }
} }
Channel::~Channel()
{
}
/** /**
* @brief * @brief
*/ */
@ -104,14 +123,6 @@ void Channel::init()
audioInput->start(dataAi); audioInput->start(dataAi);
audioInput->linkA(audioOutput); audioInput->linkA(audioOutput);
// 音量
gain = Link::create("Gain");
gain->start();
volume = Link::create("Volume");
volume->start();
gain->linkA(volume);
lineOut->linkA(gain);
// 音频编码 // 音频编码
audioEncoder = Link::create("EncodeA"); audioEncoder = Link::create("EncodeA");
audioEncoder->start(audioEncoderParams); audioEncoder->start(audioEncoderParams);
@ -166,7 +177,7 @@ void Channel::init()
audioDecoder = Link::create("DecodeA"); audioDecoder = Link::create("DecodeA");
audioDecoder->start(); audioDecoder->start();
if (channelName == Constant::MainChannel) { if (channelName == Constant::MainChannel) {
inputFile->linkA(audioDecoder)->linkA(lineOut); inputFile->linkA(audioDecoder)->linkA(gain);
} else { } else {
inputFile->linkA(audioDecoder); inputFile->linkA(audioDecoder);
} }
@ -182,8 +193,6 @@ void Channel::init()
*/ */
void Channel::startRecord() void Channel::startRecord()
{ {
QElapsedTimer mstimer;
mstimer.start();
// 记录本次录制开始时间以及当前视频录制的开始时间 // 记录本次录制开始时间以及当前视频录制的开始时间
QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss"); QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
startTime = curTime; startTime = curTime;
@ -198,9 +207,6 @@ void Channel::startRecord()
// 显示录制状态水印 // 显示录制状态水印
overlay->setData(recordOverlay); overlay->setData(recordOverlay);
float time = (double)mstimer.nsecsElapsed() / (double)1000000;
qDebug() << channelName << "startRecord cast time:" << time << "ms";
} }
/** /**
@ -211,7 +217,7 @@ void Channel::startRecord()
void Channel::onNewEvent(QString msg, QVariant data) void Channel::onNewEvent(QString msg, QVariant data)
{ {
if (msg == "newSegment") { if (msg == "newSegment") {
int id = data.toInt(); segmentId = data.toInt();
// 将上一次的文件信息存入数据库中 // 将上一次的文件信息存入数据库中
DatabaseManager::File file; DatabaseManager::File file;
file.channel = channelName == Constant::MainChannel file.channel = channelName == Constant::MainChannel
@ -223,7 +229,7 @@ void Channel::onNewEvent(QString msg, QVariant data)
file.day = currentTime.mid(6, 2); file.day = currentTime.mid(6, 2);
file.time = currentTime.mid(8, 6); file.time = currentTime.mid(8, 6);
// 设置当前视频的文件名格式本次录制开始时间_第几次分片 // 设置当前视频的文件名格式本次录制开始时间_第几次分片
file.filename = QString("%1_%2.mp4").arg(startTime).arg(id - 1); file.filename = QString("%1_%2.mp4").arg(startTime).arg(segmentId - 1);
if (db->insert(file)) { if (db->insert(file)) {
Log::info("insert one record into database success, name: {}, channel: {}", Log::info("insert one record into database success, name: {}, channel: {}",
file.filename.toStdString(), file.filename.toStdString(),
@ -235,6 +241,7 @@ void Channel::onNewEvent(QString msg, QVariant data)
} }
// 更新当前录制录制视频的时间 // 更新当前录制录制视频的时间
currentTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss"); currentTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
emit appendOneVideo(channelName);
} }
} }
@ -250,10 +257,11 @@ void Channel::stopRecord()
file.channel = channelName == Constant::MainChannel file.channel = channelName == Constant::MainChannel
? DatabaseManager::MainChannel ? DatabaseManager::MainChannel
: DatabaseManager::SecondaryChannel; : DatabaseManager::SecondaryChannel;
file.year = startTime.mid(0, 4); file.year = currentTime.mid(0, 4);
file.month = startTime.mid(4, 2); file.month = currentTime.mid(4, 2);
file.day = startTime.mid(6, 2); file.day = currentTime.mid(6, 2);
file.time = startTime.mid(8, 6); file.time = currentTime.mid(8, 6);
file.filename = QString("%1_%2.mp4").arg(startTime).arg(segmentId);
overlay->setData(norecordOverlay); overlay->setData(norecordOverlay);
} }
@ -301,7 +309,7 @@ bool Channel::startPlayback(QString path)
videoDecoder->linkV(videoOutput); videoDecoder->linkV(videoOutput);
// 断开音频信号输出,启动回放输出 // 断开音频信号输出,启动回放输出
audioInput->unLinkA(audioOutput); audioInput->unLinkA(audioOutput);
audioDecoder->linkA(lineOut); audioDecoder->linkA(gain);
playbackDuration = duration; playbackDuration = duration;
state = Playback; state = Playback;
@ -325,7 +333,7 @@ void Channel::startPlayLive()
overlay->linkV(videoOutput); overlay->linkV(videoOutput);
audioInput->linkA(audioOutput); audioInput->linkA(audioOutput);
// 关闭外部音频输出 // 关闭外部音频输出
audioDecoder->unLinkA(lineOut); audioDecoder->unLinkA(gain);
state = Stop; state = Stop;
} }
@ -405,6 +413,7 @@ void Channel::volumeUp()
QVariantMap data; QVariantMap data;
data["gain"] = curGain; data["gain"] = curGain;
gain->setData(data); gain->setData(data);
Log::info("current volumn gain: {}dB", curGain);
} }
/** /**
@ -417,6 +426,7 @@ void Channel::volumeDown()
QVariantMap data; QVariantMap data;
data["gain"] = curGain; data["gain"] = curGain;
gain->setData(data); gain->setData(data);
Log::info("current volumn gain: {}dB", curGain);
} }
/** /**

View File

@ -17,6 +17,7 @@ public:
Finish Finish
}; };
explicit Channel(QObject* parent = nullptr); explicit Channel(QObject* parent = nullptr);
~Channel();
void init(); void init();
// 录制 // 录制
@ -32,9 +33,9 @@ public:
void showFinishPromot(); void showFinishPromot();
// 音量 // 音量
QVariantMap getVolume(); static QVariantMap getVolume();
void volumeUp(); static void volumeUp();
void volumeDown(); static void volumeDown();
public: public:
QString channelName; QString channelName;
@ -47,11 +48,11 @@ public:
static LinkObject* lineIn; // 外部音频输入 static LinkObject* lineIn; // 外部音频输入
static LinkObject* resample; // 重采样 static LinkObject* resample; // 重采样
static LinkObject* lineOut; // 外部音频输出 static LinkObject* lineOut; // 外部音频输出
LinkObject* gain; // 音量增益 static LinkObject* gain; // 音量增益
LinkObject* volume; // 音量 static LinkObject* volume; // 音量
int maxGian = 30; static int maxGian; // 最大增益
int minGain = -30; static int minGain; // 最小增益
int curGain = 0; static int curGain; // 当前增益
LinkObject* audioInput; // 通道音频输入 LinkObject* audioInput; // 通道音频输入
LinkObject* audioOutput; // 通道音频输入 LinkObject* audioOutput; // 通道音频输入
@ -85,6 +86,7 @@ private slots:
signals: signals:
void playEnd(); void playEnd();
void showRecordState(bool state); void showRecordState(bool state);
void appendOneVideo(QString channelName);
private: private:
void loadOverlayConfig(); void loadOverlayConfig();

View File

@ -19,6 +19,7 @@ public:
static constexpr char* ConfigurationPath = "/opt/RecordControlApplication/configuration/config.json"; static constexpr char* ConfigurationPath = "/opt/RecordControlApplication/configuration/config.json";
static constexpr char* NetConfigPath = "/opt/RecordControlApplication/configuration/net.json"; static constexpr char* NetConfigPath = "/opt/RecordControlApplication/configuration/net.json";
static constexpr char* NetScriptPath = "/opt/RecordControlApplication/scripts/setNetwork.sh"; static constexpr char* NetScriptPath = "/opt/RecordControlApplication/scripts/setNetwork.sh";
static constexpr char* TimeSciptPath = "/opt/RecordControlApplication/scripts/rtc";
static constexpr char* DatabasePath = "/opt/RecordControlApplication/database/data.db"; static constexpr char* DatabasePath = "/opt/RecordControlApplication/database/data.db";
static constexpr char* VideoPath = "/root/usb/videos"; static constexpr char* VideoPath = "/root/usb/videos";
static constexpr char* MountedPath = "/root/usb"; static constexpr char* MountedPath = "/root/usb";

View File

@ -66,12 +66,13 @@ void DatabaseManager::close()
bool DatabaseManager::insert(File file) bool DatabaseManager::insert(File file)
{ {
QSqlQuery query; QSqlQuery query;
query.prepare("insert into file (channel, name, year, month, day) values (?, ?, ?, ?, ?)"); query.prepare("insert into file (channel, year, month, day, time, filename) values (?, ?, ?, ?, ?, ?)");
query.bindValue(0, file.channel); query.bindValue(0, file.channel);
query.bindValue(1, file.time); query.bindValue(1, file.year);
query.bindValue(2, file.year); query.bindValue(2, file.month);
query.bindValue(3, file.month); query.bindValue(3, file.day);
query.bindValue(4, file.day); query.bindValue(4, file.time);
query.bindValue(5, file.filename);
if (query.exec()) { if (query.exec()) {
return true; return true;
} else { } else {
@ -257,23 +258,55 @@ QStringList DatabaseManager::getAllDays(Channel chn, QString year, QString month
} }
/** /**
* @brief * @brief yyyyMMddhhmmss
* @param id * @param id
* @return * @return
*/ */
bool DatabaseManager::remove(DatabaseManager::Channel chn, QString name) bool DatabaseManager::remove(DatabaseManager::Channel chn, QString name)
{ {
int id = -1;
// 找到对应记录
QSqlQuery query; QSqlQuery query;
query.prepare("delet from file where channel = ? and name = ?"); query.prepare("select * from file where channel = ? and filename = ?");
query.bindValue(0, chn); query.bindValue(0, chn);
query.bindValue(1, name); query.bindValue(1, name);
if (query.exec()) { if (query.exec()) {
while (query.next()) {
id = query.value(0).toInt();
break;
}
} else {
Log::info("cannot find the record, channel = {}, name = {}",
int(chn),
name.toStdString());
return false;
}
// 未找到
if (id == -1) {
Log::info("cannot find the record, channel = {}, name = {}",
int(chn),
name.toStdString());
return false;
}
Log::info("find the record, channel = {} , name = {}, and the id = {}",
int(chn),
name.toStdString(),
id);
query.clear();
// 删除文件
query.prepare("delete from file where id = ?");
query.bindValue(0, id);
if (query.exec()) {
Log::info("delete one record from database, id = {}, channel = {}, name = {}",
id,
int(chn),
name.toStdString());
return true; return true;
} else { } else {
Log::error("delete one record from database failed, channel = {}, name = {}, reason: {}", Log::error("delete one record from database failed, channel = {}, name = {}, reason: {}",
(int)chn, (int)chn,
name.toStdString(), name.toStdString(),
query.lastError().databaseText().toStdString()); query.lastError().driverText().toStdString() + ", " + query.lastError().databaseText().toStdString());
return false; return false;
} }
} }

137
Menu.cpp
View File

@ -32,31 +32,28 @@ Menu::Menu(QWidget* parent)
ui->cmbMonth->setView(new QListView()); ui->cmbMonth->setView(new QListView());
ui->cmbDay->setView(new QListView()); ui->cmbDay->setView(new QListView());
// 设置ScrollArea为栅格布局 // 默认设置当前操作选择主通道
QGridLayout* layout = new QGridLayout(ui->scrollArea); curSelectChannel = DatabaseManager::MainChannel;
ui->scrollAreaWidgetContents->setLayout(layout); curPlayChannel = DatabaseManager::MainChannel;
db = DatabaseManager::getInstace(); db = DatabaseManager::getInstace();
if (!db->open()) if (!db->open())
return; return;
// 设置ScrollArea为栅格布局
QGridLayout* layout = new QGridLayout(ui->scrollArea);
ui->scrollAreaWidgetContents->setLayout(layout);
connect(ui->cmbYear, &QComboBox::currentTextChanged, [=](QString text) { connect(ui->cmbYear, &QComboBox::currentTextChanged, [=](QString text) {
renderComboBoxMonth(); renderComboBoxMonth();
}); });
connect(ui->cmbMonth, &QComboBox::currentTextChanged, [=](QString text) { connect(ui->cmbMonth, &QComboBox::currentTextChanged, [=](QString text) {
renderComboBoxDay(); renderComboBoxDay();
}); });
// 默认设置当前操作选择主通道
currentChannel = DatabaseManager::MainChannel;
QTimer::singleShot(200, [=] {
emit curChannelChanged(Constant::MainChannel);
});
} }
Menu::~Menu() Menu::~Menu()
{ {
delete ui; delete ui;
delete db;
} }
/** /**
@ -64,9 +61,9 @@ Menu::~Menu()
*/ */
void Menu::show() void Menu::show()
{ {
QWidget::show();
renderComboBoxYear(); renderComboBoxYear();
getContents(); getContents();
QWidget::show();
} }
/** /**
@ -75,6 +72,7 @@ void Menu::show()
*/ */
void Menu::setChannelSelectVisible(bool visible) void Menu::setChannelSelectVisible(bool visible)
{ {
channelSelectVisible = visible;
ui->widget_chnSelect->setVisible(visible); ui->widget_chnSelect->setVisible(visible);
} }
@ -83,7 +81,7 @@ void Menu::setChannelSelectVisible(bool visible)
*/ */
void Menu::renderComboBoxYear() void Menu::renderComboBoxYear()
{ {
QStringList years = db->getAllYears(currentChannel); QStringList years = db->getAllYears(curSelectChannel);
ui->cmbYear->clear(); ui->cmbYear->clear();
for (auto& str : years) { for (auto& str : years) {
@ -101,7 +99,7 @@ void Menu::renderComboBoxMonth()
if (year.isEmpty()) { if (year.isEmpty()) {
return; return;
} }
QStringList months = db->getAllMonths(currentChannel, year); QStringList months = db->getAllMonths(curSelectChannel, year);
ui->cmbMonth->clear(); ui->cmbMonth->clear();
for (auto& str : months) { for (auto& str : months) {
ui->cmbMonth->addItem(str); ui->cmbMonth->addItem(str);
@ -119,7 +117,7 @@ void Menu::renderComboBoxDay()
if (year.isEmpty() || year.isEmpty()) { if (year.isEmpty() || year.isEmpty()) {
return; return;
} }
QStringList days = db->getAllDays(currentChannel, year, month); QStringList days = db->getAllDays(curSelectChannel, year, month);
ui->cmbDay->clear(); ui->cmbDay->clear();
for (auto& str : days) { for (auto& str : days) {
ui->cmbDay->addItem(str); ui->cmbDay->addItem(str);
@ -133,7 +131,7 @@ void Menu::renderComboBoxDay()
void Menu::getContents() void Menu::getContents()
{ {
QVariantMap params; QVariantMap params;
params["channel"] = currentChannel; params["channel"] = curSelectChannel;
params["year"] = ui->cmbYear->currentText(); params["year"] = ui->cmbYear->currentText();
params["month"] = ui->cmbMonth->currentText(); params["month"] = ui->cmbMonth->currentText();
params["day"] = ui->cmbDay->currentText(); params["day"] = ui->cmbDay->currentText();
@ -155,15 +153,20 @@ void Menu::renderContents()
} }
// 重新生成若干个按钮 // 重新生成若干个按钮
for (int i = 0; i < contentList.length(); i++) { for (int i = 0; i < contentList.length(); i++) {
// 文件名格式: yyyyMMddhhmmss.mp4,只将时分秒显示到界面上 // 文件名格式: hhmmss只将时分秒显示到界面上
DatabaseManager::File file = contentList.at(i); DatabaseManager::File file = contentList.at(i);
QPushButton* btn = new QPushButton(file.time, ui->scrollArea); QString text = QString("%1:%2:%3").arg(file.time.mid(0, 2)).arg(file.time.mid(2, 2)).arg(file.time.mid(4, 2));
QPushButton* btn = new QPushButton(text, ui->scrollArea);
btn->setProperty("name", file.filename); btn->setProperty("name", file.filename);
btn->setMinimumHeight(CONTENT_CELL_HEIGHT); btn->setMinimumHeight(CONTENT_CELL_HEIGHT);
btn->setStyleSheet("QPushButton{border-radius: 5px;}"); btn->setStyleSheet("QPushButton{border-radius: 5px;}");
btn->setCheckable(true); btn->setCheckable(true);
btn->setAutoExclusive(true); btn->setAutoExclusive(true);
btn->setObjectName(QString("btn_video_%1").arg(i)); btn->setObjectName(QString("btn_video_%1").arg(i));
if (file.filename == curPlayFilename) {
btn->setChecked(true);
btn->setFocus();
}
int row = i / CONTENT_COLUMN; int row = i / CONTENT_COLUMN;
int column = i % CONTENT_COLUMN; int column = i % CONTENT_COLUMN;
layout->addWidget(btn, row, column); layout->addWidget(btn, row, column);
@ -258,11 +261,9 @@ void Menu::confirm()
QPushButton* btn = qobject_cast<QPushButton*>(focusWidget); QPushButton* btn = qobject_cast<QPushButton*>(focusWidget);
btn->setChecked(true); btn->setChecked(true);
if (btn == ui->btn_channel_1) { if (btn == ui->btn_channel_1) {
currentChannel = DatabaseManager::MainChannel; curSelectChannel = DatabaseManager::MainChannel;
emit curChannelChanged(Constant::MainChannel);
} else { } else {
currentChannel = DatabaseManager::SecondaryChannel; curSelectChannel = DatabaseManager::SecondaryChannel;
emit curChannelChanged(Constant::SecondaryChannel);
} }
renderComboBoxYear(); renderComboBoxYear();
} }
@ -289,7 +290,9 @@ void Menu::confirm()
btn->setChecked(true); btn->setChecked(true);
QString filename = btn->property("name").toString(); QString filename = btn->property("name").toString();
emit btnVideoClicked(filename); emit btnVideoClicked(filename);
currentFilename = filename; // 记录当前正在回放的通道和文件名
curPlayFilename = filename;
curPlayChannel = curSelectChannel;
} }
// 确认按钮按下确认 // 确认按钮按下确认
else if (focusWidget->objectName() == "btn_done") { else if (focusWidget->objectName() == "btn_done") {
@ -305,45 +308,68 @@ void Menu::confirm()
/** /**
* @brief * @brief
*/ */
void Menu::clickVideo(QString type) void Menu::clickPreOrNext(QString type)
{ {
getContents(); // 重新获取当前正在回放通道的视频
QVariantMap params;
params["channel"] = curPlayChannel;
params["year"] = ui->cmbYear->currentText();
params["month"] = ui->cmbMonth->currentText();
params["day"] = ui->cmbDay->currentText();
QList<DatabaseManager::File> list = db->get(params);
// 搜索当前播放视频的位置
int index = -1; int index = -1;
for (int i = 0; i < contentList.length(); i++) { for (int i = 0; i < list.length(); i++) {
DatabaseManager::File file = contentList[i]; DatabaseManager::File file = list[i];
if (file.filename == currentFilename) { if (file.filename == curPlayFilename) {
index = i; index = i;
break; break;
} }
} }
Log::info("find file filename: {}, index: {}", curPlayFilename.toStdString(), index);
// 查找目标文件名
QString filename; QString filename;
// 上一个视频
if (type == "previous") { if (type == "previous") {
// 已经是第一个视频了
if (index == 0) { if (index == 0) {
emit btnVideoClicked("first"); emit btnVideoClicked("first");
return; return;
} }
filename = contentList[index - 1].filename; index -= 1;
} } else {
// 下一个视频 // 已经是最后一个视频
else { if (index == list.length() - 1) {
if (index == contentList.length() - 1) {
emit btnVideoClicked("last"); emit btnVideoClicked("last");
return; return;
} }
filename = contentList[index + 1].filename; index += 1;
} }
filename = contentList[index + 1].filename; filename = list[index].filename;
Log::info("type: {}, index: {}, filename",
type.toStdString(),
index,
filename.toStdString());
emit btnVideoClicked(filename); emit btnVideoClicked(filename);
QString h = filename.mid(8, 2); curPlayFilename = filename;
QString m = filename.mid(10, 2); // 单通道回放
QString s = filename.mid(12, 2); if (channelSelectVisible) {
QString str = QString("%1:%2:%3").arg(h).arg(m).arg(s); // 选中通道和回放通道不是同一个时不处理
if (curPlayChannel != curSelectChannel) {
return;
}
}
// 双通道同时回放
else {
if (curPlayChannel != DatabaseManager::MainChannel) {
return;
}
}
// 选中要播放的按钮 // 选中要播放的按钮
QList<QPushButton*> btns = ui->scrollArea->findChildren<QPushButton*>(); QList<QPushButton*> btns = ui->scrollArea->findChildren<QPushButton*>();
for (QPushButton* btn : btns) { for (QPushButton* btn : btns) {
if (btn->text() == str) { if (btn->property("name").toString() == filename) {
btn->setChecked(true); btn->setChecked(true);
btn->setFocus();
} }
} }
} }
@ -365,3 +391,36 @@ QList<QWidget*> Menu::getAllFocusabelWidget()
} }
return result; return result;
} }
/**
* @brief
* @param channelName
*/
void Menu::onAppendOneVideo(QString channelName)
{
// 单通道
if (channelSelectVisible) {
// 只有生成新视频的通道和当前选择的通道一致时重新获取文件列表
if ((channelName == Constant::MainChannel
&& curSelectChannel == DatabaseManager::MainChannel)
|| (channelName == Constant::SecondaryChannel
&& curSelectChannel == DatabaseManager::SecondaryChannel)) {
renderContents();
}
}
// 双通道
else {
if (channelName == Constant::MainChannel) {
renderContents();
}
}
}
/**
* @brief
* @return
*/
DatabaseManager::Channel Menu::getCurPlayChannel()
{
return curSelectChannel;
}

12
Menu.h
View File

@ -18,11 +18,13 @@ public:
~Menu(); ~Menu();
void show(); void show();
void setChannelSelectVisible(bool visible); void setChannelSelectVisible(bool visible);
DatabaseManager::Channel getCurPlayChannel();
public slots: public slots:
void move(Direction direction); void move(Direction direction);
void confirm(); void confirm();
void clickVideo(QString type); void clickPreOrNext(QString type);
void onAppendOneVideo(QString channelName);
signals: signals:
void btnHdmi1Checked(); void btnHdmi1Checked();
@ -30,7 +32,6 @@ signals:
void btnVga1Checked(); void btnVga1Checked();
void btnVga2Checked(); void btnVga2Checked();
void btnVideoClicked(QString name); void btnVideoClicked(QString name);
void curChannelChanged(QString channel);
protected: protected:
// 重写父类的方法,以获取当前界面的所有可以获取焦点的控件 // 重写父类的方法,以获取当前界面的所有可以获取焦点的控件
@ -41,8 +42,11 @@ private:
// 视频名数组列表 // 视频名数组列表
QList<DatabaseManager::File> contentList; QList<DatabaseManager::File> contentList;
DatabaseManager* db; DatabaseManager* db;
DatabaseManager::Channel currentChannel; QString curPlayFilename; // 当前正在回放的文件名
QString currentFilename; bool channelSelectVisible = false; // 是否显示通道选择,单通道回放显示、双通道不显示
DatabaseManager::Channel curSelectChannel; // 当前选择的通道
DatabaseManager::Channel curPlayChannel; // 当前回放的通道
private: private:
void getContents(); void getContents();

View File

@ -1,123 +0,0 @@
#include "Message.h"
#include <QSpacerItem>
#include <QTimer>
#include <QVBoxLayout>
Message::Message(QWidget* parent)
: QWidget(parent)
{
btnStyle = "QPushButton { \
background: rgba(0,0,0,0.4); \
color: rgba(255,255,255); \
border: none; \
border-radius: 10px; \
min-height: 40px; \
}";
QVBoxLayout* layout = new QVBoxLayout();
layout->setContentsMargins(QMargins(10, 10, 10, 10));
layout->setSpacing(10);
this->setLayout(layout);
this->setFixedHeight(260);
QFont font;
// font.setFamily("Ubuntu Regular");
font.setPixelSize(16);
this->setFont(font);
QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
layout->addSpacerItem(verticalSpacer);
}
Message::~Message()
{
}
void Message::success(QString content, int duration)
{
showMessage(content, duration, Success);
}
void Message::info(QString content, int duration)
{
showMessage(content, duration, Info);
}
void Message::error(QString content, int duration)
{
showMessage(content, duration, Error);
}
void Message::warning(QString content, int duration)
{
showMessage(content, duration, Warning);
}
void Message::showMessage(QString content, int duration, Level level)
{
QVBoxLayout* layout = static_cast<QVBoxLayout*>(this->layout());
if (count >= maxCount) {
// remove first
QPair<QPushButton*, QTimer*> pair = contentList.first();
contentList.removeFirst();
layout->removeWidget(pair.first);
delete pair.first;
delete pair.second;
count -= 1;
}
// apeend new
QPushButton* btn = generateButton(content, level);
layout->insertWidget(count, btn);
QTimer* timer = new QTimer();
timer->setInterval(duration);
timer->start();
QPair<QPushButton*, QTimer*> pair(btn, timer);
contentList.append(pair);
count += 1;
connect(timer, &QTimer::timeout, [=] {
for (int i = 0; i < contentList.length(); i++) {
QPair<QPushButton*, QTimer*> pair = contentList.at(i);
if (pair.first == btn) {
contentList.removeAt(i);
}
layout->removeWidget(pair.first);
delete pair.first;
delete pair.second;
}
});
}
QPushButton* Message::generateButton(QString content, Level level)
{
QPushButton* btn = new QPushButton(this);
btn->setText(content);
QString iconPath;
switch (level) {
case Info:
iconPath = ":/icons/info.png";
break;
case Success:
iconPath = ":/icons/success.png";
break;
case Error:
iconPath = ":/icons/error.png";
case Warning:
iconPath = ":/icons/waring.png";
break;
default:
iconPath = ":/icons/info.png";
break;
}
btn->setIcon(QIcon(iconPath));
btn->setIconSize(QSize(16, 16));
btn->setStyleSheet(btnStyle);
QFont font = btn->font();
QFontMetrics metrics(font);
int width = metrics.boundingRect(content).size().width();
btn->setFixedWidth(width);
return btn;
}

View File

@ -1,43 +0,0 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QLabel>
#include <QPair>
#include <QPushButton>
#include <QTimer>
#include <QWidget>
class Message : public QWidget {
Q_OBJECT
public:
enum Level {
Success,
Error,
Info,
Warning
};
explicit Message(QWidget* parent = 0);
~Message();
void success(QString content, int duration);
void error(QString content, int duration);
void info(QString content, int duration);
void warning(QString content, int duration);
private:
Level level = Info;
bool isShow = false;
int count = 0;
int maxCount = 5;
QList<QPair<QPushButton*, QTimer*>> contentList;
QString btnStyle;
private:
void showMessage(QString content, int duration, Level level);
QPushButton* generateButton(QString content, Level level);
};
#endif // MESSAGE_H

View File

@ -44,7 +44,6 @@ private:
inline QString ProgressBar::msecToString(int msc) inline QString ProgressBar::msecToString(int msc)
{ {
QString formatStr = QTime(0, 0, 0).addMSecs(msc).toString(QString::fromUtf8("hh:mm:ss")); QString formatStr = QTime(0, 0, 0).addMSecs(msc).toString(QString::fromUtf8("hh:mm:ss"));
qDebug() << msc;
return formatStr; return formatStr;
} }

View File

@ -35,7 +35,6 @@ SOURCES += \
Channel.cpp \ Channel.cpp \
Menu.cpp\ Menu.cpp\
ProgressBar.cpp \ ProgressBar.cpp \
Message.cpp \
Tool.cpp \ Tool.cpp \
CheckStorageThread.cpp \ CheckStorageThread.cpp \
Constant.h \ Constant.h \
@ -54,7 +53,6 @@ HEADERS += \
Channel.h \ Channel.h \
Menu.h \ Menu.h \
ProgressBar.h \ ProgressBar.h \
Message.h \
Tool.h \ Tool.h \
CheckStorageThread.h \ CheckStorageThread.h \
Log.h \ Log.h \

View File

@ -182,6 +182,12 @@ void SerialPortTool::onReayRead()
// 返回 // 返回
emit btnReturnClicked(); emit btnReturnClicked();
break; break;
case 8:
emit btnVolumnUpClicked();
break;
case 9:
emit btnVolumnDownClicked();
break;
default: default:
break; break;
} }
@ -240,11 +246,13 @@ void SerialPortTool::onDiskNotFull()
serialPort->write(cmdMap.value(DiskNotFull)); serialPort->write(cmdMap.value(DiskNotFull));
serialPort->flush(); serialPort->flush();
} }
void SerialPortTool::onPowerOn() void SerialPortTool::onPowerOn()
{ {
serialPort->write(cmdMap.value(PowerOn)); serialPort->write(cmdMap.value(PowerOn));
serialPort->flush(); serialPort->flush();
} }
void SerialPortTool::onPowerOff() void SerialPortTool::onPowerOff()
{ {
serialPort->write(cmdMap.value(PowerOff)); serialPort->write(cmdMap.value(PowerOff));

View File

@ -51,6 +51,8 @@ signals:
void btnRightClicked(); void btnRightClicked();
void btnConfirmClicked(); void btnConfirmClicked();
void btnReturnClicked(); void btnReturnClicked();
void btnVolumnUpClicked();
void btnVolumnDownClicked();
private: private:
enum CommandType { enum CommandType {

View File

@ -23,6 +23,7 @@ void TcpConnectionHandler::onReadyRead()
{ {
bool ret = request->readFromSocket(socket); bool ret = request->readFromSocket(socket);
if (!ret) { if (!ret) {
response->setUrl("Unkown Url");
response->error(request->getErrorString()); response->error(request->getErrorString());
return; return;
} }

View File

@ -5,6 +5,7 @@
#include "Json.h" #include "Json.h"
#include "Log.h" #include "Log.h"
#include "Tool.h" #include "Tool.h"
#include <QCoreApplication>
#include <QDir> #include <QDir>
#include <QProcess> #include <QProcess>
@ -183,7 +184,7 @@ void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse)
{ {
QVariantMap params = request->getBodyParams(); QVariantMap params = request->getBodyParams();
QString chn = params.value("interface").toString(); QString chn = params.value("interface").toString();
if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) { if (chn != Constant::MainChannel && chn != Constant::SecondaryChannel) {
Log::error("getFileList params error, error param \"interface\""); Log::error("getFileList params error, error param \"interface\"");
reponse->error("接口参数错误"); reponse->error("接口参数错误");
return; return;
@ -192,11 +193,15 @@ void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse)
: DatabaseManager::SecondaryChannel; : DatabaseManager::SecondaryChannel;
QString interface = params.value("interface").toString(); QString interface = params.value("interface").toString();
QList<DatabaseManager::File> fileList = db->get(channel); QList<DatabaseManager::File> fileList = db->get(channel);
QStringList result; QVariantList result;
for (const DatabaseManager::File& file : fileList) { for (const DatabaseManager::File& file : fileList) {
result.push_back(file.filename); QString time = file.year + file.month + file.day + file.time;
QVariantMap fileInfo;
fileInfo["time"] = time;
fileInfo["filename"] = file.filename;
result.push_back(fileInfo);
} }
reponse->success("获取文件成功", result); reponse->success("获取文件成功", QVariant::fromValue(result));
} }
/** /**
@ -208,7 +213,7 @@ void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse)
QVariantMap params = request->getBodyParams(); QVariantMap params = request->getBodyParams();
QString chn = params.value("interface").toString(); QString chn = params.value("interface").toString();
QString filename = params.value("filename").toString(); QString filename = params.value("filename").toString();
if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) { if (chn != Constant::MainChannel && chn != Constant::SecondaryChannel) {
Log::error("deleteFile params error, error params \"interface\" or \"filename\""); Log::error("deleteFile params error, error params \"interface\" or \"filename\"");
reponse->error("通道参数错误"); reponse->error("通道参数错误");
return; return;
@ -218,18 +223,24 @@ void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse)
reponse->error("缺少文件名参数"); reponse->error("缺少文件名参数");
return; return;
} }
// 从数据库删除指定记录 // 先查找是否存在物理文件,再查找数据库中是否有对应记,然后一一删除
DatabaseManager::Channel channel = chn == Constant::MainChannel // 删除对应的视频文件
? DatabaseManager::MainChannel
: DatabaseManager::SecondaryChannel;
db->remove(channel, filename);
// 删除相对于的视频文件
QString filePath = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn).arg(filename); QString filePath = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn).arg(filename);
QFile video(filePath); QFile video(filePath);
if (video.exists()) { if (video.exists()) {
// 删除数据库记录
DatabaseManager::Channel channel = chn == Constant::MainChannel
? DatabaseManager::MainChannel
: DatabaseManager::SecondaryChannel;
bool ret = db->remove(channel, filename);
if (!ret) {
reponse->error("文件不存在");
return;
} else {
video.remove(); video.remove();
Log::info("remove video {}", filePath.toStdString()); Log::info("remove video {}", filePath.toStdString());
reponse->success("删除成功"); reponse->success("删除成功");
}
} else { } else {
Log::error("error, file: {} dont exist", filePath.toStdString()); Log::error("error, file: {} dont exist", filePath.toStdString());
reponse->error("文件不存在"); reponse->error("文件不存在");
@ -315,9 +326,7 @@ void TcpRequestHandler::reboot(TcpRequest* request, TcpResponse* reponse)
chn->stopRecord(); chn->stopRecord();
} }
reponse->success("重启成功"); reponse->success("重启成功");
qApp->quit();
// 退出程序等待后台运行的shell脚本重启程序
exit(0);
} }
/** /**
@ -334,7 +343,7 @@ void TcpRequestHandler::setCurrentTime(TcpRequest* request, TcpResponse* reponse
} }
QString time = params.value("time").toString(); QString time = params.value("time").toString();
QString cmd = QString("/link/bin/rtc -s time %1").arg(time); QString cmd = QString("%1 -s time \"%2\"").arg(Constant::TimeSciptPath).arg(time);
QString result = Tool::writeCom(cmd); QString result = Tool::writeCom(cmd);
// 修改成功会返回类似信息, "Tue Mar 5 15:51:18 CST 2024" // 修改成功会返回类似信息, "Tue Mar 5 15:51:18 CST 2024"
if (result.isEmpty()) { if (result.isEmpty()) {

View File

@ -1,4 +1,5 @@
#include "Tool.h" #include "Tool.h"
#include "QTimer"
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QElapsedTimer> #include <QElapsedTimer>

View File

@ -46,6 +46,7 @@ Widget::Widget(QWidget* parent)
for (Channel* chn : channelList) { for (Channel* chn : channelList) {
connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd())); connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd()));
connect(chn, SIGNAL(showRecordState(bool)), this, SLOT(onShowRecordLabel(bool))); connect(chn, SIGNAL(showRecordState(bool)), this, SLOT(onShowRecordLabel(bool)));
connect(chn, SIGNAL(appendOneVideo(QString)), menu, SLOT(onAppendOneVideo(QString)));
// 监听输入信号的变化 // 监听输入信号的变化
connect(chn->videoInput, &LinkObject::newEvent, [=](QString type, QVariant msg) { connect(chn->videoInput, &LinkObject::newEvent, [=](QString type, QVariant msg) {
if (type == "signal") { if (type == "signal") {
@ -81,10 +82,11 @@ Widget::Widget(QWidget* parent)
connect(serialPortTool, SIGNAL(btnRightClicked()), this, SLOT(onBtnRightClicked())); connect(serialPortTool, SIGNAL(btnRightClicked()), this, SLOT(onBtnRightClicked()));
connect(serialPortTool, SIGNAL(btnConfirmClicked()), this, SLOT(onBtnConfirmClicked())); connect(serialPortTool, SIGNAL(btnConfirmClicked()), this, SLOT(onBtnConfirmClicked()));
connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked())); connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked()));
connect(serialPortTool, SIGNAL(btnVolumnUpClicked()), this, SLOT(onBtnVolumnUpClicked()));
connect(serialPortTool, SIGNAL(btnVolumnDownClicked()), this, SLOT(onBtnVolumnDownClicked()));
connect(menu, SIGNAL(curChannelChanged(QString)), this, SLOT(onCurChannelChanged(QString)));
connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString))); connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString)));
connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickVideo(QString))); connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickPreOrNext(QString)));
} }
Widget::~Widget() Widget::~Widget()
@ -134,7 +136,6 @@ void Widget::onBtnReturnClicked()
if (chn->state != Channel::Stop) { if (chn->state != Channel::Stop) {
chn->startPlayLive(); chn->startPlayLive();
serialPortTool->onPlaybackEnd(); serialPortTool->onPlaybackEnd();
curPlayFilename = "";
} }
} }
// 隐藏进度条并关闭定时器 // 隐藏进度条并关闭定时器
@ -232,12 +233,29 @@ void Widget::onBtnConfirmClicked()
} }
} }
/**
* @brief
*/
void Widget::onBtnVolumnUpClicked()
{
Channel::volumeUp();
}
/**
* @brief
*/
void Widget::onBtnVolumnDownClicked()
{
Channel::volumeDown();
}
/** /**
* @brief * @brief
*/ */
void Widget::onBtnVideoClicked(QString filename) void Widget::onBtnVideoClicked(QString filename)
{ {
if (filename == "first") { if (filename == "first") {
qDebug() << "click previous failed, already the first video";
// 显示提示弹窗 // 显示提示弹窗
} else if (filename == "last") { } else if (filename == "last") {
if (playbackMode == Constant::OneChannelPlayback) { if (playbackMode == Constant::OneChannelPlayback) {
@ -257,18 +275,16 @@ void Widget::onBtnVideoClicked(QString filename)
} }
} }
void Widget::onCurChannelChanged(QString channel)
{
curSelectChannel = channel;
Log::info("channel switch, current channel:", channel.toStdString());
}
/** /**
* @brief HDMI-OUT0口输出 * @brief HDMI-OUT0口输出
*/ */
void Widget::playOneChannel(QString filename) void Widget::playOneChannel(QString filename)
{ {
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curSelectChannel).arg(filename); // 获取当前回放的通道
QString curPlayChannel = menu->getCurPlayChannel() == DatabaseManager::MainChannel
? Constant::MainChannel
: Constant::SecondaryChannel;
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curPlayChannel).arg(filename);
Channel* channel = findChannelByName(Constant::MainChannel); Channel* channel = findChannelByName(Constant::MainChannel);
for (Channel* chn : channelList) { for (Channel* chn : channelList) {
chn->startPlayLive(); chn->startPlayLive();
@ -280,10 +296,7 @@ void Widget::playOneChannel(QString filename)
} }
isPlayback = true; isPlayback = true;
curPlayChannel = curSelectChannel; // 全局保存当前播放的视频的文件名
curPlayFilename = filename;
// 全局保存当前播放的视频
mutex.lock(); mutex.lock();
curFilename = filename; curFilename = filename;
condition.wakeAll(); condition.wakeAll();
@ -334,12 +347,8 @@ void Widget::playTwoChannels(QString filename)
} }
} }
} }
curPlayFilename = filename;
curPlayChannel = Constant::MainChannel;
isPlayback = true; isPlayback = true;
// 全局保存正在播放的视频的文件名
// 全局保存正在播放的视频
mutex.lock(); mutex.lock();
curFilename = filename; curFilename = filename;
condition.wakeAll(); condition.wakeAll();
@ -374,6 +383,8 @@ void Widget::seek(QString type)
*/ */
void Widget::onPlayEnd() void Widget::onPlayEnd()
{ {
// 停下回放计时器
progressTimer->stop();
// 当两路回放时,只处理一次槽函数 // 当两路回放时,只处理一次槽函数
if (playbackMode == Constant::TwoChannelPlayback) { if (playbackMode == Constant::TwoChannelPlayback) {
LinkObject* file = static_cast<LinkObject*>(sender()); LinkObject* file = static_cast<LinkObject*>(sender());

View File

@ -3,7 +3,6 @@
#include "Channel.h" #include "Channel.h"
#include "Menu.h" #include "Menu.h"
#include "Message.h"
#include "ProgressBar.h" #include "ProgressBar.h"
#include <QDir> #include <QDir>
#include <QMap> #include <QMap>
@ -36,20 +35,17 @@ private slots:
void onBtnRightClicked(); void onBtnRightClicked();
void onBtnConfirmClicked(); void onBtnConfirmClicked();
void onBtnReturnClicked(); void onBtnReturnClicked();
void onBtnVolumnUpClicked();
void onBtnVolumnDownClicked();
// 播放视频 // 播放视频
void onBtnVideoClicked(QString filename); void onBtnVideoClicked(QString filename);
void onCurChannelChanged(QString channel);
private: private:
Ui::Widget* ui; Ui::Widget* ui;
QTimer* progressTimer; QTimer* progressTimer;
bool isPlayback = false; bool isPlayback = false;
QString curPlayChannel;
QString curSelectChannel;
QString curPlayFilename;
Menu* menu; Menu* menu;
private: private:

View File

@ -23,6 +23,8 @@ DatabaseManager* db;
// 视频输出通道 // 视频输出通道
LinkObject* vo; LinkObject* vo;
LinkObject* vo1; LinkObject* vo1;
// 硬盘检测现场
CheckStorageThread* thread;
// 通道列表 // 通道列表
QList<Channel*> channelList; QList<Channel*> channelList;
@ -135,6 +137,20 @@ void setChannelProtocol()
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
qDebug() << (R"(
____ _ _____
/ ___|| |__ __ _ _ __ | ___|__ _ __ __ _
\___ \| '_ \ / _` | '_ \| |_ / _ \ '_ \ / _` |
___) | | | | (_| | | | | _| __/ | | | (_| |
|____/|_| |_|\__,_|_| |_|_| \___|_| |_|\__, |
|___/ )");
qDebug() << (R"(
____ _ _ _ __ __ _
/ ___|| |_ __ _ _ __| |_ ___ __| | \ \ / /__| | ___ ___ _ __ ___ ___
\___ \| __/ _` | '__| __/ _ \/ _` | \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
___) | || (_| | | | || __/ (_| | \ V V / __/ | (_| (_) | | | | | | __/
|____/ \__\__,_|_| \__\___|\__,_| \_/\_/ \___|_|\___\___/|_| |_| |_|\___|
)");
// std::atexit(resetLight); // std::atexit(resetLight);
// 初始化日志 // 初始化日志
Log::init(); Log::init();
@ -218,7 +234,7 @@ int main(int argc, char* argv[])
w.show(); w.show();
// 硬盘检测线程,检测硬盘容量 // 硬盘检测线程,检测硬盘容量
CheckStorageThread* thread = new CheckStorageThread(); thread = new CheckStorageThread();
thread->start(); thread->start();
QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull())); QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull()));
QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull())); QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull()));