From d1d86556450a3b20d87a4b0abcb9127af1716252 Mon Sep 17 00:00:00 2001 From: zc Date: Sun, 11 Aug 2024 20:26:42 -0700 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=8F=9C=E5=8D=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Channel.cpp | 273 +++++++-- Channel.h | 63 ++- ChannelSetting.cpp | 140 ----- ChannelSetting.h | 29 - ChannelSetting.ui | 269 --------- CheckStorageThread.cpp | 24 +- Constant.h | 10 +- DatabaseManager.cpp | 279 ++++++++++ DatabaseManager.h | 48 ++ FocusWindow.cpp | 320 +++++++++++ FocusWindow.h | 53 ++ Log.cpp | 1 + Menu.cpp | 404 ++++++++++++-- Menu.h | 77 ++- Menu.ui | 1010 ++++++++++++++++++++++++++++++---- ProgressBar.cpp | 4 +- ProgressBar.h | 8 +- ProgressBar.ui | 6 + RecordControlApplication.pro | 11 +- SerialPortTool.cpp | 37 +- SerialPortTool.cpp.bak | 327 +++++++++++ SerialPortTool.h | 15 +- SerialPortTool.h.bak | 88 +++ TcpRequestHandler.cpp | 53 +- Tool.cpp | 16 + Tool.h | 5 + Widget.cpp | 671 +++++++++------------- Widget.h | 33 +- Widget.ui | 241 +++++--- main.cpp | 61 +- 30 files changed, 3289 insertions(+), 1287 deletions(-) delete mode 100644 ChannelSetting.cpp delete mode 100644 ChannelSetting.h delete mode 100644 ChannelSetting.ui create mode 100755 DatabaseManager.cpp create mode 100755 DatabaseManager.h create mode 100755 FocusWindow.cpp create mode 100755 FocusWindow.h create mode 100644 SerialPortTool.cpp.bak create mode 100644 SerialPortTool.h.bak diff --git a/Channel.cpp b/Channel.cpp index fd686f8..e426ecf 100755 --- a/Channel.cpp +++ b/Channel.cpp @@ -1,5 +1,7 @@ #include "Channel.h" #include "Constant.h" +#include "DatabaseManager.h" +#include "Json.h" #include "Log.h" #include "Tool.h" #include @@ -8,40 +10,50 @@ #include #include -LinkObject* Channel::audioInput = nullptr; -LinkObject* Channel::audioOutput = nullptr; +#include + +LinkObject* Channel::lineIn = nullptr; +LinkObject* Channel::lineOut = nullptr; LinkObject* Channel::rtspServer = nullptr; -QString Channel::curRecordFilename = ""; +LinkObject* Channel::resample = nullptr; extern LinkObject* vo; extern LinkObject* vo1; +extern DatabaseManager* db; Channel::Channel(QObject* parent) : QObject(parent) { videoInput = nullptr; videoOutput = nullptr; + audioInput = nullptr; + audioOutput = nullptr; videoEncoder = nullptr; audioEncoder = nullptr; record = nullptr; rtsp = nullptr; - file = nullptr; + inputFile = nullptr; videoDecoder = nullptr; audioDecoder = nullptr; image = Link::create("InputImage"); - if (audioInput == nullptr) { - audioInput = Link::create("InputAlsa"); + if (lineIn == nullptr) { + lineIn = Link::create("InputAlsa"); QVariantMap dataIn; dataIn["path"] = "hw:0,0"; dataIn["channels"] = 2; - audioInput->start(dataIn); + lineIn->start(dataIn); } - if (audioOutput == nullptr) { - audioOutput = Link::create("OutputAlsa"); + if (resample = nullptr) { + resample = Link::create("Resample"); + resample->start(); + lineIn->linkA(resample); + } + if (lineOut == nullptr) { + lineOut = Link::create("OutputAlsa"); QVariantMap dataOut; dataOut["path"] = "hw:0,0"; - audioOutput->start(dataOut); + lineOut->start(dataOut); } if (rtspServer == nullptr) { rtspServer = Link::create("Rtsp"); @@ -58,11 +70,22 @@ void Channel::init() Log::error("channel name is empty!"); return; } + // 通道音频输出 + audioOutput = Link::create("OutputAo"); + QVariantMap dataVo; if (channelName == Constant::MainChannel) { videoOutput = vo; + dataVo["interface"] = "HDMI-OUT0"; } else { videoOutput = vo1; + dataVo["interface"] = "HDMI-OUT1"; } + loadOverlayConfig(); + + // 水印,用于显示录制状态 + overlay = Link::create("Overlay"); + overlay->start(norecordOverlay); + overlay->linkV(videoOutput); // 视频输入 videoInput = Link::create("InputVi"); @@ -71,35 +94,54 @@ void Channel::init() dataVi["width"] = 1920; dataVi["height"] = 1080; videoInput->start(dataVi); - videoInput->linkV(videoOutput); + videoInput->linkV(overlay)->linkV(videoOutput); - // 视频编码 - videoEncoder = Link::create("EncodeV"); - videoEncoder->start(videoEncoderParams); + // 通道音频输入 + audioInput = Link::create("InputAi"); + QVariantMap dataAi; + dataAi["interface"] = channelName; + dataAi["channels"] = 2; + audioInput->start(dataAi); + 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->start(audioEncoderParams); + // 视频编码 + videoEncoder = Link::create("EncodeV"); + videoEncoder->start(videoEncoderParams); + // 录制 record = Link::create("Mux"); QVariantMap dataMp4; dataMp4["format"] = "mp4"; - dataMp4["segmentDuration"] = duration; + dataMp4["filecache"] = 20480000; dataMp4["lowLatency"] = true; - // dataMp4["filecache"] = 20480000; + dataMp4["thread"] = true; + dataMp4["segmentDuration"] = duration; record->setData(dataMp4); videoInput->linkV(videoEncoder)->linkV(record); - audioInput->linkA(audioEncoder)->linkA(record); + audioInput->linkV(audioEncoder)->linkV(record); + resample->linkA(audioEncoder)->linkA(record); - connect(record, &LinkObject::newEvent, [=](QString type, QVariant data) { - if (type == "newSegment") { - int id = data.toInt(); - curRecordFilename = QString("%1_%2.mp4") - .arg(curRecordFilename.split("_")[0]) - .arg(id, 2, 10, QLatin1Char('0')); - } - }); + connect(record, SIGNAL(newEvent(QString, QVariant)), this, SLOT(onNewEvent(QString, QVariant))); + // 测试执行时间,用时18-20ms + // connect(record, &LinkObject::newEvent, [=](QString msg, QVariant data) { + // Tool::getCostTime( + // [=] { + // onNewEvent(msg, data); + // }, + // "onNewEvent"); + // }); // rstp流 rtsp = Link::create("Mux"); @@ -108,11 +150,12 @@ void Channel::init() dataRtsp["format"] = "rtsp"; rtsp->start(dataRtsp); videoInput->linkV(videoEncoder)->linkV(rtsp)->linkV(rtspServer); - audioInput->linkA(audioEncoder)->linkA(rtsp)->linkA(rtspServer); + audioInput->linkA(audioEncoder)->linkV(rtsp)->linkV(rtspServer); + resample->linkA(audioEncoder)->linkA(rtsp)->linkA(rtspServer); // 播放文件 - file = Link::create("InputFile"); - connect(file, &LinkObject::newEvent, [=](QString type, QVariant msg) { + inputFile = Link::create("InputFile"); + connect(inputFile, &LinkObject::newEvent, [=](QString type, QVariant msg) { if (type == "EOF") { Log::info("{} one video playback end", channelName.toStdString()); emit playEnd(); @@ -123,15 +166,15 @@ void Channel::init() audioDecoder = Link::create("DecodeA"); audioDecoder->start(); if (channelName == Constant::MainChannel) { - file->linkA(audioDecoder)->linkA(audioOutput); + inputFile->linkA(audioDecoder)->linkA(lineOut); } else { - file->linkA(audioDecoder); + inputFile->linkA(audioDecoder); } // 视频解码 videoDecoder = Link::create("DecodeV"); videoDecoder->start(); - file->linkV(videoDecoder)->linkV(videoOutput); + inputFile->linkV(videoDecoder)->linkV(videoOutput); } /** @@ -139,19 +182,60 @@ void Channel::init() */ void Channel::startRecord() { - // 阻塞到整分钟才开始录制,方便上位机进行回放 - while (int secs = QTime::currentTime().second() % 60 != 0) { - QCoreApplication::processEvents(); - } - QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmm"); - curRecordFilename = curTime + "_00.mp4"; + QElapsedTimer mstimer; + mstimer.start(); + // 记录本次录制开始时间以及当前视频录制的开始时间 + QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss"); + startTime = curTime; + currentTime = curTime; QVariantMap dataRecord; - QString path = QString("%1/%2/%3.mp4").arg(Constant::VideoPath).arg(channelName).arg(curTime + "_%02d"); + QString path = QString("%1/%2/%3_%d.mp4").arg(Constant::VideoPath).arg(channelName).arg(curTime); dataRecord["path"] = path; record->start(dataRecord); isRecord = true; Log::info("{} start recording...", channelName.toStdString()); - emit showRecordState(true); + Log::info("open done {}", path.toStdString()); + + // 显示录制状态水印 + overlay->setData(recordOverlay); + + float time = (double)mstimer.nsecsElapsed() / (double)1000000; + qDebug() << channelName << "startRecord cast time:" << time << "ms"; +} + +/** + * @brief 新事件槽函数 + * @param msg 时间类型 + * @param data 数据 + */ +void Channel::onNewEvent(QString msg, QVariant data) +{ + if (msg == "newSegment") { + int id = data.toInt(); + // 将上一次的文件信息存入数据库中 + DatabaseManager::File file; + file.channel = channelName == Constant::MainChannel + ? DatabaseManager::MainChannel + : DatabaseManager::SecondaryChannel; + // 设置当前视频的录制时间信息 + file.year = currentTime.mid(0, 4); + file.month = currentTime.mid(4, 2); + file.day = currentTime.mid(6, 2); + file.time = currentTime.mid(8, 6); + // 设置当前视频的文件名,格式:本次录制开始时间_第几次分片 + file.filename = QString("%1_%2.mp4").arg(startTime).arg(id - 1); + if (db->insert(file)) { + Log::info("insert one record into database success, name: {}, channel: {}", + file.filename.toStdString(), + channelName.toStdString()); + } else { + Log::error("insert one record into database failed, name: {}, channel: {}", + file.filename.toStdString(), + channelName.toStdString()); + } + // 更新当前录制录制视频的时间 + currentTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss"); + } } /** @@ -161,7 +245,16 @@ void Channel::stopRecord() { Log::info("{} stop recording...", channelName.toStdString()); record->stop(true); - emit showRecordState(false); + // 将录制文件的信息存入数据库 + DatabaseManager::File file; + file.channel = channelName == Constant::MainChannel + ? DatabaseManager::MainChannel + : DatabaseManager::SecondaryChannel; + file.year = startTime.mid(0, 4); + file.month = startTime.mid(4, 2); + file.day = startTime.mid(6, 2); + file.time = startTime.mid(8, 6); + overlay->setData(norecordOverlay); } /** @@ -177,7 +270,6 @@ bool Channel::startPlayback(QString path) videoInput->unLinkV(videoOutput); QVariantMap dataImage; dataImage["path"] = Constant::EmptyImagePath; - image->setData(dataImage); image->start(dataImage); image->linkV(videoOutput); state = Error; @@ -187,26 +279,30 @@ bool Channel::startPlayback(QString path) // 开始回放 QVariantMap dataFile; dataFile["path"] = path; - dataFile["async"] = false; - file->start(dataFile); + dataFile["sync"] = true; + inputFile->start(dataFile); // 判断视频是否损坏,如果损坏则输出提示图片 - int duration = file->invoke("getDuration", path).toInt() / 1000; + int duration = inputFile->invoke("getDuration", path).toInt(); if (duration == 0) { Log::error("cannot open video {}, video file was corrupted", path.toStdString()); - file->stop(); + inputFile->stop(); videoInput->unLinkV(videoOutput); QVariantMap dataImage; dataImage["path"] = Constant::ErrorImagePath; - image->setData(dataImage); image->start(dataImage); image->linkV(videoOutput); state = Error; return false; } - videoInput->unLinkV(videoOutput); + // 断开视频信号输出,启动回放输出 + overlay->unLinkV(videoOutput); videoDecoder->linkV(videoOutput); + // 断开音频信号输出,启动回放输出 + audioInput->unLinkA(audioOutput); + audioDecoder->linkA(lineOut); + playbackDuration = duration; state = Playback; return true; @@ -219,12 +315,17 @@ void Channel::startPlayLive() { if (state == Playback) { videoDecoder->unLinkV(videoOutput); - file->stop(true); + audioDecoder->unLinkA(audioOutput); + inputFile->stop(true); } else if (state == Error) { image->unLinkV(videoOutput); image->stop(true); } - videoInput->linkV(videoOutput); + // 打开视频和音频输出 + overlay->linkV(videoOutput); + audioInput->linkA(audioOutput); + // 关闭外部音频输出 + audioDecoder->unLinkA(lineOut); state = Stop; } @@ -234,9 +335,9 @@ void Channel::startPlayLive() void Channel::back() { Log::info("{} back 10s", channelName.toStdString()); - int curPos = file->invoke("getPosition").toInt(); + int curPos = inputFile->invoke("getPosition").toInt(); curPos -= 10 * 1000; - file->invoke("seek", curPos); + inputFile->invoke("seek", curPos); } /** @@ -245,9 +346,9 @@ void Channel::back() void Channel::forward() { Log::info("{} forward 10s", channelName.toStdString()); - int curPos = file->invoke("getPosition").toInt(); + int curPos = inputFile->invoke("getPosition").toInt(); curPos += 10 * 1000; - file->invoke("seek", curPos); + inputFile->invoke("seek", curPos); } /** @@ -261,7 +362,7 @@ void Channel::togglePause() state = Pause; else state = Playback; - file->invoke("pause", state == Pause); + inputFile->invoke("pause", state == Pause); } /** @@ -272,8 +373,68 @@ void Channel::showFinishPromot() videoInput->unLinkV(videoDecoder); QVariantMap dataImage; dataImage["path"] = Constant::FinishImagePath; - image->setData(dataImage); image->start(dataImage); image->linkV(videoOutput); state = Finish; -} \ No newline at end of file +} + +/** + * @brief 获取音量 + * @return L左声道音量,R右声道音量 + */ +QVariantMap Channel::getVolume() +{ + QVariantMap result; + QVariantMap data = volume->invoke("getVolume").toMap(); + result["L"] = data["max"].toInt(); + if (data["avg"].toInt() < 15) + result["L"] = 0; + result["R"] = data["max2"].toInt(); + if (data["avg2"].toInt() < 15) + result["R"] = 0; + return result; +} + +/** + * @brief 增大音量 + */ +void Channel::volumeUp() +{ + if (curGain < maxGian) + curGain += 6; + QVariantMap data; + data["gain"] = curGain; + gain->setData(data); +} + +/** + * @brief 减小音量 + */ +void Channel::volumeDown() +{ + if (curGain > minGain) + curGain -= 6; + QVariantMap data; + data["gain"] = curGain; + gain->setData(data); +} + +/** + * @brief 将水印配置属性加载到内存中 + */ +void Channel::loadOverlayConfig() +{ + auto loadFromJson = [](const QString& path) { + QVariantMap dataOver; + QVariantList list = Json::loadFile(path).toList(); + QVariantList list2; + for (int i = 0; i < list.count(); i++) { + QVariantMap map = list[i].toMap(); + list2 << map; + } + dataOver["lays"] = list2; + return dataOver; + }; + recordOverlay = loadFromJson(Constant::RecordOverlay); + norecordOverlay = loadFromJson(Constant::NoRecordOverlay); +} diff --git a/Channel.h b/Channel.h index 2465740..15b11ea 100755 --- a/Channel.h +++ b/Channel.h @@ -1,6 +1,7 @@ #ifndef CHANNEL_H #define CHANNEL_H +#include "Json.h" #include "Link.h" #include #include @@ -18,6 +19,24 @@ public: explicit Channel(QObject* parent = nullptr); void init(); + // 录制 + void startRecord(); + void stopRecord(); + + // 回放 + bool startPlayback(QString path); + void forward(); + void back(); + void togglePause(); + void startPlayLive(); + void showFinishPromot(); + + // 音量 + QVariantMap getVolume(); + void volumeUp(); + void volumeDown(); + +public: QString channelName; LinkObject* videoInput; @@ -25,40 +44,50 @@ public: QVariantMap videoEncoderParams; LinkObject* videoOutput; - static LinkObject* audioInput; - static LinkObject* audioOutput; - LinkObject* audioEncoder; - QVariantMap audioEncoderParams; + static LinkObject* lineIn; // 外部音频输入 + static LinkObject* resample; // 重采样 + static LinkObject* lineOut; // 外部音频输出 + LinkObject* gain; // 音量增益 + LinkObject* volume; // 音量 + int maxGian = 30; + int minGain = -30; + int curGain = 0; + + LinkObject* audioInput; // 通道音频输入 + LinkObject* audioOutput; // 通道音频输入 + LinkObject* audioEncoder; // 音频编码器 + QVariantMap audioEncoderParams; // 编码参数 LinkObject* record; int duration = 1 * 60 * 1000; // 单个视频时长 bool isRecord = false; - static QString curRecordFilename; // 当前正在录制的文件名 + QString startTime; // 本次录制文件的开始时间 + QString currentTime; // 当前录制文件的开始时间 + int segmentId = 0; + LinkObject* overlay; // 水印,提示是否在录制视频 + QVariantMap recordOverlay; // 录制状态下的水印参数 + QVariantMap norecordOverlay; // 非录制状态下的水印参数 - int playbackDuration = 0; - LinkObject* file; - LinkObject* image; + int playbackDuration = 0; // 当前播放视频的时长,单位ms + LinkObject* inputFile; LinkObject* videoDecoder; LinkObject* audioDecoder; + LinkObject* image; PlaybackState state = Stop; static LinkObject* rtspServer; LinkObject* rtsp; QString pushCode; - void startRecord(); - void stopRecord(); - bool startPlayback(QString path); - void forward(); - void back(); - void togglePause(); - - void startPlayLive(); - void showFinishPromot(); +private slots: + void onNewEvent(QString msg, QVariant data); signals: void playEnd(); void showRecordState(bool state); + +private: + void loadOverlayConfig(); }; #endif // CHANNEL_H diff --git a/ChannelSetting.cpp b/ChannelSetting.cpp deleted file mode 100644 index 030d1f6..0000000 --- a/ChannelSetting.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "ChannelSetting.h" -#include "Constant.h" -#include "SerialPortTool.h" -#include "ui_ChannelSetting.h" -#include -#include -#include -#include -#include - -extern SerialPortTool* serialPortTool; - -ChannelSetting::ChannelSetting(QWidget* parent) - : QWidget(parent) - , ui(new Ui::ChannelSetting) -{ - ui->setupUi(this); - - QPoint globalPos = parent->mapToGlobal(QPoint(0, 0)); - int x = globalPos.x() + (parent->width() - this->width()) / 2; - int y = globalPos.y() + (parent->height() - this->height()) / 2; - this->move(x, y); -} - -ChannelSetting::~ChannelSetting() -{ - delete ui; -} - -/** - * @brief 重写show方法 - */ -void ChannelSetting::show() -{ - // 默认聚焦确定按钮 - ui->btnDone->setFocus(); - // 获取配置文件中保存的输入源类型(HDMI or VGA) - QVariantMap config = Json::loadFile(Constant::ConfigurationPath).toMap(); - QVariantList list = config["interface"].toList(); - for (int i = 0; i < list.count(); i++) { - QVariantMap cfg = list.at(i).toMap(); - QString channelName = cfg["name"].toString(); - QString protocol = cfg["protocol"].toString(); - if (channelName == Constant::MainChannel) { - protocol1 = protocol; - } else { - protocol2 = protocol; - } - } - if (protocol1 == "HDMI") { - ui->btn_hdmi_1->setChecked(true); - } else { - ui->btn_vga_1->setChecked(true); - } - if (protocol2 == "HDMI") { - ui->btn_hdmi_2->setChecked(true); - } else { - ui->btn_vga_2->setChecked(true); - } - QWidget::show(); -} - -void ChannelSetting::onReceiveNext() -{ - QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier); - QApplication::sendEvent(focusWidget(), &keyEvent); - - QKeyEvent keyEvent1(QEvent::KeyRelease, Qt::Key_Down, Qt::NoModifier); - QApplication::sendEvent(focusWidget(), &keyEvent1); -} - -void ChannelSetting::onReceivePre() -{ - QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier); - QApplication::sendEvent(focusWidget(), &keyEvent); - - QKeyEvent keyEvent1(QEvent::KeyRelease, Qt::Key_Up, Qt::NoModifier); - QApplication::sendEvent(focusWidget(), &keyEvent1); -} - -void ChannelSetting::onReceiveEnter() -{ - // 聚焦的控件 - QString objName = focusWidget()->objectName(); - // 通道一 - if (objName.endsWith("1")) { - if (objName == "btn_hdmi_1") { - ui->btn_hdmi_1->setChecked(true); - ui->btn_vga_1->setChecked(false); - protocol1 = "HDMI"; - } else { - ui->btn_hdmi_1->setChecked(false); - ui->btn_vga_1->setChecked(true); - protocol1 = "VGA"; - } - } - // 通道二 - else if (objName.endsWith("2")) { - if (objName == "btn_hdmi_2") { - ui->btn_hdmi_2->setChecked(true); - ui->btn_vga_2->setChecked(false); - protocol2 = "HDMI"; - } else { - ui->btn_hdmi_2->setChecked(false); - ui->btn_vga_2->setChecked(true); - protocol2 = "VGA"; - } - } - // 确认按钮 - else { - // 保存配置 - QVariantMap config = Json::loadFile(Constant::ConfigurationPath).toMap(); - QVariantList list = config["interface"].toList(); - for (int i = 0; i < list.count(); i++) { - QVariantMap cfg = list.at(i).toMap(); - QString channelName = cfg["name"].toString(); - if (channelName == Constant::MainChannel) { - cfg["protocol"] = protocol1; - } else { - cfg["protocol"] = protocol2; - } - list[i] = cfg; - } - config["interface"] = list; - Json::saveFile(config, Constant::ConfigurationPath); - // 发送指令 - if (protocol1 == "HDMI") { - serialPortTool->onMainChannelHDMI(); - } else { - serialPortTool->onMainChannelVGA(); - } - QThread::msleep(100); - if (protocol2 == "HDMI") { - serialPortTool->onSecondaryChannelHDMI(); - } else { - serialPortTool->onSecondaryChannelVGA(); - } - hide(); - } -} \ No newline at end of file diff --git a/ChannelSetting.h b/ChannelSetting.h deleted file mode 100644 index aa5a9be..0000000 --- a/ChannelSetting.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CHANNELSETTING_H -#define CHANNELSETTING_H - -#include - -namespace Ui { -class ChannelSetting; -} - -class ChannelSetting : public QWidget { - Q_OBJECT - -public: - explicit ChannelSetting(QWidget* parent = 0); - ~ChannelSetting(); - void show(); - -public slots: - void onReceiveEnter(); - void onReceivePre(); - void onReceiveNext(); - -private: - Ui::ChannelSetting* ui; - QString protocol1; // 通道1输入信号类型 - QString protocol2; // 通道2输入信号类型 -}; - -#endif // CHANNELSETTING_H diff --git a/ChannelSetting.ui b/ChannelSetting.ui deleted file mode 100644 index 9d1bdce..0000000 --- a/ChannelSetting.ui +++ /dev/null @@ -1,269 +0,0 @@ - - - ChannelSetting - - - - 0 - 0 - 391 - 307 - - - - Form - - - QPushButton { - outline: none; - border: none; -} - -QPushButton:focus { - border: 5px solid red; -} - -QPushButton:checked { - background: blue; -} - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QWidget { - color: #ffffff; -} - -QWidget#widget{ - background: rgba(0, 0, 0, 0.8); -} - -QPushButton { - outline: none; - border: none; - background: rgba(100,100,100,0.8); -} - -QPushButton:focus { - border: 5px solid red; -} - -QPushButton:checked { - background: rgba(0,0,255,0.8); -} - - - - - - - 14 - - - - 视频源设置 - - - Qt::AlignCenter - - - - - - - - - - 16777213 - 16777215 - - - - - 12 - - - - 通道1 - - - Qt::AlignCenter - - - - - - - 10 - - - 10 - - - - - - 0 - 0 - - - - - 12 - - - - HDMI - - - true - - - - - - - - 0 - 0 - - - - - 12 - - - - VGA - - - true - - - - - - - - - - - - - - 16777213 - 16777215 - - - - - 12 - - - - 通道2 - - - Qt::AlignCenter - - - - - - - 10 - - - 10 - - - - - - 0 - 0 - - - - - 12 - - - - HDMI - - - true - - - - - - - - 0 - 0 - - - - - 12 - - - - VGA - - - true - - - - - - - - - - - - 0 - 40 - - - - - 12 - - - - background: rgba(0,0,255,0.8); - - - 确定 - - - - - - - - - - - diff --git a/CheckStorageThread.cpp b/CheckStorageThread.cpp index e8c34e2..5228847 100755 --- a/CheckStorageThread.cpp +++ b/CheckStorageThread.cpp @@ -1,5 +1,6 @@ #include "CheckStorageThread.h" #include "Constant.h" +#include "DatabaseManager.h" #include "Log.h" #include "Tool.h" #include @@ -14,6 +15,7 @@ extern QString curFilename; extern QMutex mutex; extern QWaitCondition condition; +extern DatabaseManager* db; CheckStorageThread::CheckStorageThread() { @@ -29,10 +31,13 @@ void CheckStorageThread::run() if (available < THRESHOLD) { Log::info("there are not enough storage, then remove some files..."); emit diskWillFull(); - // 获取文件列表 - QStringList fileList = Tool::getFileList(QString("%1/%2").arg(Constant::VideoPath).arg(Constant::MainChannel)); - if (!fileList.isEmpty()) { - QString filename = fileList.first(); + // 从数据库中取出前两条数据,找到相关的文件删除 + QList fileList = db->getTopTwo(); + for (auto& file : fileList) { + QString filename = file.time; + QString channel = file.channel == DatabaseManager::MainChannel + ? Constant::MainChannel + : Constant::SecondaryChannel; // 判断文件是否再回放,如果在回放就阻塞等待 mutex.lock(); if (filename == curFilename) { @@ -42,20 +47,15 @@ void CheckStorageThread::run() } mutex.unlock(); // 删除文件 - QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(Constant::MainChannel).arg(filename); + QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(channel).arg(filename); bool ret = Tool::removeFile(path); if (!ret) { Log::error("remove file {} failed", path.toStdString()); } else { Log::info("remove file {} success", path.toStdString()); } - path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(Constant::SecondaryChannel).arg(filename); - ret = Tool::removeFile(path); - if (!ret) { - Log::error("remove file {} failed", path.toStdString()); - } else { - Log::info("remove file {} success", path.toStdString()); - } + // 从数据库清除这条记录 + db->remove(file.channel, file.time); } } else { emit diskNotFull(); diff --git a/Constant.h b/Constant.h index 1b3b626..4b7206c 100755 --- a/Constant.h +++ b/Constant.h @@ -3,7 +3,7 @@ class Constant { public: - Constant() { } + Constant() {} enum RecordMode { NoChannelRecord, OneChannelRecord, @@ -14,17 +14,21 @@ public: OneChannelPlayback = 1, TwoChannelPlayback = 2 }; + static constexpr char* LogPath = "/opt/RecordControlApplication/logs/log.txt"; static constexpr char* ConfigurationPath = "/opt/RecordControlApplication/configuration/config.json"; static constexpr char* NetConfigPath = "/opt/RecordControlApplication/configuration/net.json"; static constexpr char* NetScriptPath = "/opt/RecordControlApplication/scripts/setNetwork.sh"; + static constexpr char* DatabasePath = "/opt/RecordControlApplication/database/data.db"; static constexpr char* VideoPath = "/root/usb/videos"; static constexpr char* MountedPath = "/root/usb"; static constexpr char* ErrorImagePath = "/opt/RecordControlApplication/images/error.jpeg"; static constexpr char* EmptyImagePath = "/opt/RecordControlApplication/images/empty.jpeg"; static constexpr char* FinishImagePath = "/opt/RecordControlApplication/images/finish.jpeg"; - static constexpr char* MainChannel = "HDMI-C"; - static constexpr char* SecondaryChannel = "HDMI-D"; + static constexpr char* MainChannel = "HDMI-A"; + static constexpr char* SecondaryChannel = "HDMI-B"; + static constexpr char* RecordOverlay = "/opt/RecordControlApplication/overlay/record.json"; + static constexpr char* NoRecordOverlay = "/opt/RecordControlApplication/overlay/no-record.json"; }; #endif // CONSTANT_H diff --git a/DatabaseManager.cpp b/DatabaseManager.cpp new file mode 100755 index 0000000..5cc7a28 --- /dev/null +++ b/DatabaseManager.cpp @@ -0,0 +1,279 @@ +#include "DatabaseManager.h" +#include "Constant.h" +#include "Log.h" +#include +#include +#include +#include + +DatabaseManager* DatabaseManager::instance = nullptr; + +DatabaseManager::DatabaseManager() +{ + if (QSqlDatabase::contains("qt_sql_default_connection")) { + db = QSqlDatabase::database("qt_sql_default_connection"); + } else { + db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(Constant::DatabasePath); + } +} + +DatabaseManager::~DatabaseManager() +{ + db.close(); +} + +DatabaseManager* DatabaseManager::getInstace() +{ + if (instance == nullptr) { + static QMutex mutex; + QMutexLocker locker(&mutex); + if (instance == nullptr) { + instance = new DatabaseManager(); + } + } + return instance; +} + +/** + * @brief 打开数据库 + * @return + */ +bool DatabaseManager::open() +{ + if (!db.open()) { + Log::error("database open failed"); + qDebug() << db.lastError(); + return false; + } + Log::info("database open success"); + return true; +} + +/** + * @brief 关闭数据库 + */ +void DatabaseManager::close() +{ + if (db.isOpen()) + db.close(); +} + +/** + * @brief 添加数据 + * @param file + */ +bool DatabaseManager::insert(File file) +{ + QSqlQuery query; + query.prepare("insert into file (channel, name, year, month, day) values (?, ?, ?, ?, ?)"); + query.bindValue(0, file.channel); + query.bindValue(1, file.time); + query.bindValue(2, file.year); + query.bindValue(3, file.month); + query.bindValue(4, file.day); + if (query.exec()) { + return true; + } else { + Log::error("insert one record into database failed, reason: {}", + query.lastError().databaseText().toStdString()); + return false; + } +} + +/** + * @brief 查询数据 + * @param params 参数 + * @return + */ +QList DatabaseManager::get(QVariantMap params) +{ + QList result; + QSqlQuery query; + QString sql = "select * from file where channel=? and year = ? and month = ? and day = ?"; + QString year = params.value("year").toString(); + QString month = params.value("month").toString(); + QString day = params.value("day").toString(); + Channel chn = static_cast(params.value("channel").toInt()); + query.prepare(sql); + query.bindValue(0, chn); + query.bindValue(1, year); + query.bindValue(2, month); + query.bindValue(3, day); + if (year.isEmpty() || month.isEmpty() || day.isEmpty() || (chn != MainChannel && chn != SecondaryChannel)) { + Log::error("select from database error, params error"); + return result; + } + if (query.exec()) { + while (query.next()) { + DatabaseManager::File file; + file.id = query.value("id").toInt(); + file.year = query.value("year").toString(); + file.month = query.value("month").toString(); + file.day = query.value("day").toString(); + file.channel = static_cast(query.value("channel").toInt()); + file.time = query.value("time").toString(); + file.filename = query.value("filename").toString(); + result.push_back(file); + } + } else { + Log::error("select from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + Log::info("record of one day: {}", result.length()); + return result; +} + +/** + * @brief 获取某个通道的所有文件列表 + * @param chn + * @return + */ +QList DatabaseManager::get(DatabaseManager::Channel chn) +{ + QList result; + QSqlQuery query; + QString sql = "select * from file where channel=?"; + query.prepare(sql); + query.bindValue(0, chn); + if (query.exec()) { + while (query.next()) { + DatabaseManager::File file; + file.id = query.value("id").toInt(); + file.year = query.value("year").toString(); + file.month = query.value("month").toString(); + file.day = query.value("day").toString(); + file.channel = static_cast(query.value("channel").toInt()); + file.time = query.value("time").toString(); + file.filename = query.value("filename").toString(); + result.push_back(file); + } + } else { + Log::error("select from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + return result; +} + +/** + * @brief 获取前两条记录 + */ +QList DatabaseManager::getTopTwo() +{ + QList result; + QSqlQuery query; + query.prepare("select * from file limit 0,2"); + if (query.exec()) { + while (query.next()) { + DatabaseManager::File file; + file.id = query.value("id").toInt(); + file.year = query.value("year").toString(); + file.month = query.value("month").toString(); + file.day = query.value("day").toString(); + file.channel = static_cast(query.value("channel").toInt()); + file.time = query.value("time").toString(); + file.filename = query.value("filename").toString(); + result.push_back(file); + } + } else { + Log::error("select top two records from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + return result; +} + +/** + * @brief 获取所有的年份 + * @return + */ +QStringList DatabaseManager::getAllYears(Channel chn) +{ + QStringList result; + QSqlQuery query; + query.prepare("select distinct year from file"); + if (query.exec()) { + while (query.next()) { + QString year = query.value(0).toString(); + result.push_back(year); + } + } else { + Log::error("select all years from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + Log::info("number of year: {}", result.length()); + return result; +} + +/** + * @brief 获取某年所有的月份 + * @param year + * @return + */ +QStringList DatabaseManager::getAllMonths(Channel chn, QString year) +{ + QStringList result; + QSqlQuery query; + query.prepare("select distinct month from file where channel = ? and year=?"); + query.bindValue(0, chn); + query.bindValue(1, year); + if (query.exec()) { + while (query.next()) { + QString month = query.value(0).toString(); + result.push_back(month); + } + } else { + Log::error("select all months of one year from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + Log::info("number of month: {}", result.length()); + return result; +} + +/** + * @brief 某年某月的天数 + * @param year + * @param month + * @return + */ +QStringList DatabaseManager::getAllDays(Channel chn, QString year, QString month) +{ + QStringList result; + QSqlQuery query; + query.prepare("select distinct day from file where channel = ? and year=? and month=?"); + query.bindValue(0, chn); + query.bindValue(1, year); + query.bindValue(2, month); + if (query.exec()) { + while (query.next()) { + QString day = query.value(0).toString(); + result.push_back(day); + } + } else { + Log::error("select all days of one month from database failed, reason: {}", + query.lastError().databaseText().toStdString()); + } + Log::info("number of day: {}", result.length()); + return result; +} + +/** + * @brief 根据通道和文件名删除记录 + * @param id + * @return + */ +bool DatabaseManager::remove(DatabaseManager::Channel chn, QString name) +{ + QSqlQuery query; + query.prepare("delet from file where channel = ? and name = ?"); + query.bindValue(0, chn); + query.bindValue(1, name); + if (query.exec()) { + return true; + } else { + Log::error("delete one record from database failed, channel = {}, name = {}, reason: {}", + (int)chn, + name.toStdString(), + query.lastError().databaseText().toStdString()); + return false; + } +} diff --git a/DatabaseManager.h b/DatabaseManager.h new file mode 100755 index 0000000..5173718 --- /dev/null +++ b/DatabaseManager.h @@ -0,0 +1,48 @@ +#ifndef DATABASEMANAGER_H +#define DATABASEMANAGER_H +#include +#include + +// 数据库管理类 +class DatabaseManager { +public: + enum Channel { + MainChannel = 1, + SecondaryChannel + }; + struct File { + int id; // id + Channel channel; // 通道 + QString year; // 年 + QString month; // 月 + QString day; // 日 + QString time; // 时分秒,hh:mm:ss + QString filename; // 真实路径 + }; + static DatabaseManager* getInstace(); + ~DatabaseManager(); + + bool open(); + void close(); + + bool insert(File file); + + bool remove(DatabaseManager::Channel chn, QString name); + + QList getTopTwo(); + + QList get(QVariantMap params); + QList get(Channel chn); + QStringList getAllYears(Channel chn); + QStringList getAllMonths(Channel chn, QString year); + QStringList getAllDays(Channel, QString year, QString month); + +private: + DatabaseManager(); + +private: + static DatabaseManager* instance; + QSqlDatabase db; +}; + +#endif // DATABASEMANAGER_H diff --git a/FocusWindow.cpp b/FocusWindow.cpp new file mode 100755 index 0000000..e1e3dda --- /dev/null +++ b/FocusWindow.cpp @@ -0,0 +1,320 @@ +#include +#include "FocusWindow.h" + +using namespace FW; + +/** + * @brief жijؼǷΪijϵĺѡؼ + * @param focused ǰ۽Ŀؼȫλ + * @param focusable ǰӵнĿؼȫλ + * @param direction + * @return + */ +bool FocusWindow::isCandidate(QRect focused, QRect focusable, Direction direction) +{ + switch (direction) + { + case Up: + return (focused.bottom() > focusable.bottom() || focused.top() >= focusable.bottom()) + && focused.top() > focusable.top(); + case Down: + return (focused.top() < focusable.top() || focused.bottom() <= focusable.top()) + && focused.bottom() < focusable.bottom(); + case Left: + return (focused.right() > focused.right() || focused.left() >= focusable.right()) + && focused.left() > focusable.left(); + case Right: + return (focused.left() < focusable.left() || focused.right() <= focusable.left()) + && focused.right() < focusable.right(); + default: + return false; + } +} + +/** + * @brief жrect1rect2directionǷص + * @param direction + * @param rect1 һ + * @param rect2 ڶ + * @return + */ +bool FocusWindow::beamsOverlap(Direction direction, QRect rect1, QRect rect2) +{ + switch (direction) + { + case Left: + case Right: + return (rect2.bottom() >= rect1.top()) && (rect2.top() <= rect1.bottom()); + case Up: + case Down: + return (rect2.right() >= rect1.left()) && (rect2.left() <= rect1.right()); + } +} + +/** + * @brief жdestǷsourcedirection + * @param direction + * @param source + * @param dest + * @return + */ +bool FocusWindow::isToDirectionOf(Direction direction, QRect source, QRect dest) +{ + switch (direction) + { + case Up: + return source.top() >= dest.bottom(); + case Down: + return source.bottom() <= dest.top(); + case Left: + return source.left() >= dest.right(); + case Right: + return source.right() <= dest.left(); + } +} + +/** + * @brief ᷽ϵľ + * @param direction + * @param source + * @param dest + * @return + */ +int FocusWindow::majorAxisDistance(Direction direction, QRect source, QRect dest) +{ + return qMax(0, majorAxisDistanceRaw(direction, source, dest)); +} + +/** + * @brief ᷽ľ + * @param direction + * @param source + * @param dest + * @return + */ +int FocusWindow::majorAxisDistanceRaw(Direction direction, QRect source, QRect dest) +{ + switch (direction) + { + case Up: + return source.top() - dest.bottom(); + case Down: + return dest.top() - source.bottom(); + case Left: + return source.left() - dest.right(); + case Right: + return dest.left() - source.right(); + default: + return 0; + } +} + +/** + * @brief ᷽Ե + * @param dircetion + * @param source + * @param dest + * @return + */ +int FocusWindow::majorAxisDistanceToFarEdge(Direction dircetion, QRect source, QRect dest) +{ + return qMax(1, majorAxisDistanceToFarEdgeRaw(dircetion, source, dest)); +} + +/** + * @brief ᷽Ե + * @param dircetion + * @param source + * @param dest + * @return + */ +int FocusWindow::majorAxisDistanceToFarEdgeRaw(Direction dircetion, QRect source, QRect dest) +{ + switch (dircetion) + { + case Up: + return source.top() - dest.top(); + case Down: + return dest.bottom() - source.bottom(); + case Left: + return source.left() - dest.left(); + case Right: + return dest.right() - source.right(); + default: + return 0; + } +} + +/** + * @brief 㸱᷽ϵľ(ĵľ) + * @param direction + * @param source + * @param dest + * @return + */ +int FocusWindow::minorAxisDistance(Direction direction, QRect source, QRect dest) +{ + switch (direction) + { + case Up: + case Down: + return qAbs((source.left() + source.width() / 2) - (dest.left() + dest.width() / 2)); + case Left: + case Right: + return qAbs((source.top() + source.height() / 2) - (dest.top() + dest.height() / 2)); + default: + return 0; + } +} + +/** + * @brief ۺϾ, 㹫ʽ 13 * major^2 + minor ^ 2(13ΪȨ) + * @param direction + * @param majorAxisDistance ᷽ľ + * @param minorAxisDistance ᷽ľ + * @return + */ +int FocusWindow::getWeightDistanceFor(int majorAxisDistance, int minorAxisDistance) +{ + return 13 * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance; +} + +/** + * @brief жrect1rect2sourcedircetionǷ + * @param dircetion + * @param source + * @param rect1 һ + * @param rect2 ڶ + * @return + */ +bool FocusWindow::beamBeats(Direction direction, QRect source, QRect rect1, QRect rect2) +{ + bool rect1InSrcBeam = beamsOverlap(direction, source, rect1); + bool rect2InSrcBeam = beamsOverlap(direction, source, rect2); + // rect2صrect1ص + if (rect2InSrcBeam || !rect1InSrcBeam) + { + return false; + } + // rect1صrect2ص + // + // rect2Ƿdirection + if (!isToDirectionOf(direction, source, rect2)) + { + return true; + } + + // ˮƽһ + if (direction == Left || direction == Right) + { + return true; + } + return (majorAxisDistance(direction, source, rect1) + < majorAxisDistanceToFarEdge(direction, source, rect2)); +} + +/** + * @brief жǷǸõĺѡ + * @param direction + * @param focused ǰ۽Ŀؼȫλ + * @param focusable ǰ۽Ŀؼȫλ + * @param curCandidate ǰѺѡȫλ + * @return + */ +bool FocusWindow::isBetterCandidate(Direction direction, QRect focused, QRect focusable, QRect curCandidate) +{ + // ǰĿؼ(direction) + if (!isCandidate(focused, focusable, direction)) + { + return false; + } + // ѡؼ + if (!isCandidate(focused, curCandidate, direction)) + return true; + // ǰĿؼԭĺѡؼжԱ + if (beamBeats(direction, focused, focusable, curCandidate)) + { + return true; + } + // ǰѡؼ뵱ǰؼжԱ + if (beamBeats(direction, focused, curCandidate, focusable)) + { + return false; + } + + // 㵱ǰؼ۽ؼۺϾǷСںѡؼ۽ؼۺϾ + return (getWeightDistanceFor(majorAxisDistance(direction, focused, focusable), + minorAxisDistance(direction, focused, focusable)) + < getWeightDistanceFor(majorAxisDistance(direction, focused, curCandidate), + minorAxisDistance(direction, focused, curCandidate))); +} + +/** + * @brief ָһؼ + * @param direction + * @return + */ +QWidget* FocusWindow::getNextFocusWidget(Direction direction) +{ + focusableList = getAllFocusabelWidget(); + QWidget* nextFocus = nullptr; + // ѡб + QList candidates; + + QWidget* focusedWidget = QApplication::focusWidget(); + if (!focusedWidget) + return nextFocus; + + // 㵱ǰ۽ؼȫλ + QRect focusedRect = QRect(focusedWidget->mapToGlobal(QPoint(0, 0)), focusedWidget->size()); + // 鹹һѡԭλ෴ƶһ + QRect betterCandidateRect = focusedRect; + switch (direction) + { + case Up: + betterCandidateRect = QRect(QPoint(focusedRect.x(), focusedRect.y() + 1), focusedRect.size()); + break; + case Down: + betterCandidateRect = QRect(QPoint(focusedRect.x(), focusedRect.y() - 1), focusedRect.size()); + break; + case Left: + betterCandidateRect = QRect(QPoint(focusedRect.x() + 1, focusedRect.y()), focusedRect.size()); + break; + case Right: + betterCandidateRect = QRect(QPoint(focusedRect.x() - 1, focusedRect.y()), focusedRect.size()); + break; + default: + break; + } + // ѭȽϿؼλãҵкѡؼ + for (int i = 0; i < focusableList.length(); i++) + { + QWidget* focusable = focusableList.at(i); + // ɾ۽ؼǵǰýĿؼתȽ + if (focusable == focusedWidget) + continue; + // ɾ۽ؼλתΪȫֵλ + QRect focusableRect = QRect(focusable->mapToGlobal(QPoint(0, 0)), focusable->size()); + // ǷΪźѡ + if (isBetterCandidate(direction, focusedRect, focusableRect, betterCandidateRect)) + { + betterCandidateRect = focusableRect; + nextFocus = focusable; + } + } + return nextFocus; +} + +/** + * @brief ۽һؼ + * @param direction + */ +void FocusWindow::focusNext(Direction direction) +{ + QWidget* nextFocus = getNextFocusWidget(direction); + if (nextFocus) + { + nextFocus->setFocus(); + } +} + diff --git a/FocusWindow.h b/FocusWindow.h new file mode 100755 index 0000000..03dce62 --- /dev/null +++ b/FocusWindow.h @@ -0,0 +1,53 @@ +/***************************************************************** + * @file FocusWindow.h + * @brief qt役ܹƶ࣬ڲʵȫandroidԴ뽹ƶ֡ + * ʹõʱҪ̳༴ɲдgetAllFocusabelWidget + * @author luoxiang + * @date May 23 2024 +****************************************************************/ +#include +#ifndef FOCUS_WINDOW_H +#define FOCUS_WINDOW_H + +namespace FW +{ + class FocusWindow + { + public: + // ƶ + enum Direction + { + Up, + Down, + Left, + Right + }; + void focusNext(Direction direction); + + protected: + // 麯дԻȡǰпԻýĿؼ + virtual QList getAllFocusabelWidget() = 0; + + private: + QList focusableList; + + private: + // 뽹ƶصĺ + QWidget* getNextFocusWidget(Direction direction); + bool isCandidate(QRect focused, QRect focusable, Direction direction); + bool isBetterCandidate(Direction direction, QRect focused, QRect focusable, QRect curCandidate); + bool beamBeats(Direction dircetion, QRect source, QRect rect1, QRect rect2); + bool beamsOverlap(Direction direction, QRect rect1, QRect rect2); + bool isToDirectionOf(Direction direction, QRect source, QRect dest); + int majorAxisDistance(Direction direction, QRect source, QRect dest); + int majorAxisDistanceRaw(Direction direction, QRect source, QRect dest); + int minorAxisDistance(Direction direction, QRect source, QRect dest); + int getWeightDistanceFor(int majorAxisDistance, int minorAxisDistance); + int majorAxisDistanceToFarEdge(Direction dircetion, QRect source, QRect dest); + int majorAxisDistanceToFarEdgeRaw(Direction dircetion, QRect source, QRect dest); + }; +} + +#endif // !FOCUS_WINDOW_H + + diff --git a/Log.cpp b/Log.cpp index a6e94f5..d03a6be 100644 --- a/Log.cpp +++ b/Log.cpp @@ -3,6 +3,7 @@ #include "spdlog/sinks/daily_file_sink.h" #include "spdlog/sinks/stdout_sinks.h" #include "spdlog/spdlog.h" +#include #include #include diff --git a/Menu.cpp b/Menu.cpp index 6e36ffc..3c4a4e0 100755 --- a/Menu.cpp +++ b/Menu.cpp @@ -1,37 +1,367 @@ -#include "Menu.h" -#include "Constant.h" -#include "ui_Menu.h" - -Menu::Menu(QWidget* parent) - : QWidget(parent) - , ui(new Ui::Menu) -{ - ui->setupUi(this); - ui->btnChannelA->setChecked(true); - - QPoint globalPos = parent->mapToGlobal(QPoint(0, 0)); - int x = globalPos.x() + (parent->width() - this->width()) / 2; - int y = globalPos.y() + (parent->height() - this->height()) / 2; - this->move(x, y); -} - -Menu::~Menu() -{ - delete ui; -} - -QString Menu::getCurChannel() -{ - if (ui->btnChannelA->isChecked()) - return Constant::MainChannel; - else - return Constant::SecondaryChannel; -} - -void Menu::setCurChannel(QString channel) -{ - if (channel == Constant::MainChannel) - ui->btnChannelA->setChecked(true); - else - ui->btnChannelB->setChecked(true); -} +#include "Menu.h" +#include "Constant.h" +#include "DatabaseManager.h" +#include "Log.h" +#include "ui_Menu.h" +#include +#include +#include +#include + +#define CONTENT_ROW 6 // 列表行 +#define CONTENT_COLUMN 6 // 列表列 +#define CONTENT_CELL_HEIGHT 56 // 单元格高度 + +Menu::Menu(QWidget* parent) + : QWidget(parent) + , FocusWindow() + , ui(new Ui::Menu) +{ + ui->setupUi(this); + setAttribute(Qt::WA_WState_WindowOpacitySet); + setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + setWindowOpacity(0.5); + setFixedSize(800, 600); + ui->stackedWidget->setCurrentIndex(0); + ui->btnChannelSetting->setFocus(); + + QDesktopWidget* deskdop = QApplication::desktop(); + QWidget::move((deskdop->width() - this->width()) / 2, (deskdop->height() - this->height()) / 2); + + ui->cmbYear->setView(new QListView()); + ui->cmbMonth->setView(new QListView()); + ui->cmbDay->setView(new QListView()); + + // 设置ScrollArea为栅格布局 + QGridLayout* layout = new QGridLayout(ui->scrollArea); + ui->scrollAreaWidgetContents->setLayout(layout); + + db = DatabaseManager::getInstace(); + if (!db->open()) + return; + + connect(ui->cmbYear, &QComboBox::currentTextChanged, [=](QString text) { + renderComboBoxMonth(); + }); + connect(ui->cmbMonth, &QComboBox::currentTextChanged, [=](QString text) { + renderComboBoxDay(); + }); + // 默认设置当前操作选择主通道 + currentChannel = DatabaseManager::MainChannel; + QTimer::singleShot(200, [=] { + emit curChannelChanged(Constant::MainChannel); + }); +} + +Menu::~Menu() +{ + delete ui; + delete db; +} + +/** + * @brief 重写菜单show方法 + */ +void Menu::show() +{ + renderComboBoxYear(); + getContents(); + QWidget::show(); +} + +/** + * @brief 设置是否显示通道选择 + * @param visible + */ +void Menu::setChannelSelectVisible(bool visible) +{ + ui->widget_chnSelect->setVisible(visible); +} + +/** + * @brief 渲染年份 + */ +void Menu::renderComboBoxYear() +{ + QStringList years = db->getAllYears(currentChannel); + + ui->cmbYear->clear(); + for (auto& str : years) { + ui->cmbYear->addItem(str); + } + ui->cmbYear->setCurrentIndex(0); +} + +/** + * @brief 渲染月份 + */ +void Menu::renderComboBoxMonth() +{ + QString year = ui->cmbYear->currentText(); + if (year.isEmpty()) { + return; + } + QStringList months = db->getAllMonths(currentChannel, year); + ui->cmbMonth->clear(); + for (auto& str : months) { + ui->cmbMonth->addItem(str); + } + ui->cmbMonth->setCurrentIndex(0); +} + +/** + * @brief 渲染天数 + */ +void Menu::renderComboBoxDay() +{ + QString year = ui->cmbYear->currentText(); + QString month = ui->cmbMonth->currentText(); + if (year.isEmpty() || year.isEmpty()) { + return; + } + QStringList days = db->getAllDays(currentChannel, year, month); + ui->cmbDay->clear(); + for (auto& str : days) { + ui->cmbDay->addItem(str); + } + ui->cmbDay->setCurrentIndex(0); +} + +/** + * @brief 获取数据 + */ +void Menu::getContents() +{ + QVariantMap params; + params["channel"] = currentChannel; + params["year"] = ui->cmbYear->currentText(); + params["month"] = ui->cmbMonth->currentText(); + params["day"] = ui->cmbDay->currentText(); + contentList = db->get(params); + renderContents(); +} + +/** + * @brief 将视频名称列表渲染成一堆按钮放到ScrollArea中,6*6 + */ +void Menu::renderContents() +{ + QGridLayout* layout = qobject_cast(ui->scrollAreaWidgetContents->layout()); + + // 清除原来的控件防止内存泄漏 + QList widgets = ui->scrollAreaWidgetContents->findChildren(); + for (QWidget* w : widgets) { + delete w; + } + // 重新生成若干个按钮 + for (int i = 0; i < contentList.length(); i++) { + // 文件名格式: yyyyMMddhhmmss.mp4,只将时分秒显示到界面上 + DatabaseManager::File file = contentList.at(i); + QPushButton* btn = new QPushButton(file.time, ui->scrollArea); + btn->setProperty("name", file.filename); + btn->setMinimumHeight(CONTENT_CELL_HEIGHT); + btn->setStyleSheet("QPushButton{border-radius: 5px;}"); + btn->setCheckable(true); + btn->setAutoExclusive(true); + btn->setObjectName(QString("btn_video_%1").arg(i)); + int row = i / CONTENT_COLUMN; + int column = i % CONTENT_COLUMN; + layout->addWidget(btn, row, column); + } + + // 少于36个用空的widget占位置 + if (contentList.length() < CONTENT_ROW * CONTENT_COLUMN) { + int lastRow = (contentList.length() - 1) / CONTENT_COLUMN; + int lastColum = (contentList.length() - 1) % CONTENT_COLUMN; + + for (int i = lastRow; i < CONTENT_ROW; i++) { + for (int j = 0; j < CONTENT_COLUMN; j++) { + if (i == lastRow && j <= lastColum) { + continue; + } + QWidget* widget = new QWidget(ui->scrollArea); + widget->setMinimumHeight(CONTENT_CELL_HEIGHT); + layout->addWidget(widget, i, j); + } + } + } +} + +/** + * @brief 移动 + * @param direction + */ +void Menu::move(Direction direction) +{ + QWidget* focusWidget = QApplication::focusWidget(); + // 当前焦点是否在展开后的ComboBox上 + bool isCmbPopup = (strcmp(focusWidget->metaObject()->className(), "QListView") == 0); + // 下拉框展开,则只进行上下选择 + if (isCmbPopup) { + // 随便赋值一个不影响功能的按键 + Qt::Key key = Qt::Key_Right; + if (direction == Up) { + key == Qt::Key_Up; + } else if (direction == Down) { + key == Qt::Key_Down; + } + QKeyEvent pressEvent(QEvent::KeyPress, key, Qt::NoModifier); + QApplication::sendEvent(focusWidget, &pressEvent); + QKeyEvent releaseEvent(QEvent::KeyRelease, key, Qt::NoModifier); + QApplication::sendEvent(focusWidget, &releaseEvent); + } else { + focusNext(direction); + focusWidget = QApplication::focusWidget(); + int drawedHeight = focusWidget->visibleRegion().boundingRect().height(); + int height = focusWidget->height(); + // 绘制的高度小于实际高度,则表示控件显示不完全 + if (drawedHeight < height) { + ui->scrollArea->ensureWidgetVisible(focusWidget); + } + if (focusWidget == ui->btnChannelSetting) { + ui->btnChannelSetting->setChecked(true); + ui->stackedWidget->setCurrentIndex(0); + } else if (focusWidget == ui->btnPlayback) { + ui->btnPlayback->setChecked(true); + ui->stackedWidget->setCurrentIndex(1); + } + } +} + +/** + * @brief 确认 + */ +void Menu::confirm() +{ + int index = ui->stackedWidget->currentIndex(); + QWidget* focusWidget = QApplication::focusWidget(); + switch (index) { + // 通道设置界面 + case 0: { + QPushButton* btn = qobject_cast(focusWidget); + btn->setChecked(true); + if (btn == ui->btn_hdmi_1) { + emit btnHdmi1Checked(); + } else if (btn == ui->btn_hdmi_2) { + emit btnHdmi2Checked(); + } else if (btn == ui->btn_vga_1) { + emit btnVga1Checked(); + } else if (btn == ui->btn_vga_2) { + emit btnVga2Checked(); + } + break; + } + // 回放界面 + case 1: { + // 通道选择时按下确认 + if (focusWidget == ui->btn_channel_1 || focusWidget == ui->btn_channel_2) { + QPushButton* btn = qobject_cast(focusWidget); + btn->setChecked(true); + if (btn == ui->btn_channel_1) { + currentChannel = DatabaseManager::MainChannel; + emit curChannelChanged(Constant::MainChannel); + } else { + currentChannel = DatabaseManager::SecondaryChannel; + emit curChannelChanged(Constant::SecondaryChannel); + } + renderComboBoxYear(); + } + // 下拉框未展开时按下确认 + else if (strcmp(focusWidget->metaObject()->className(), "QComboBox") == 0) { + QComboBox* cmb = qobject_cast(focusWidget); + cmb->showPopup(); + } + // 下拉框展开时按下确认 + else if (strcmp(focusWidget->metaObject()->className(), "QListView") == 0) { + // QComboBox的层级 + // QComboBox + // |- QComboBoxPrivateContainer(Popup widget) + // |- QListView(or QListWidget) + // |-QViewPort(Child of QListView) + QComboBox* cmb = static_cast(focusWidget->parent()->parent()); + if (cmb) { + cmb->hidePopup(); + } + } + // 选择视频时按下确认 + else if (focusWidget->objectName().contains("btn_video")) { + QPushButton* btn = qobject_cast(focusWidget); + btn->setChecked(true); + QString filename = btn->property("name").toString(); + emit btnVideoClicked(filename); + currentFilename = filename; + } + // 确认按钮按下确认 + else if (focusWidget->objectName() == "btn_done") { + getContents(); + } + break; + } + default: + break; + } +} + +/** + * @brief 点击查找当前列表中的上一个视频和下一个视频 + */ +void Menu::clickVideo(QString type) +{ + getContents(); + int index = -1; + for (int i = 0; i < contentList.length(); i++) { + DatabaseManager::File file = contentList[i]; + if (file.filename == currentFilename) { + index = i; + break; + } + } + QString filename; + // 上一个视频 + if (type == "previous") { + if (index == 0) { + emit btnVideoClicked("first"); + return; + } + filename = contentList[index - 1].filename; + } + // 下一个视频 + else { + if (index == contentList.length() - 1) { + emit btnVideoClicked("last"); + return; + } + filename = contentList[index + 1].filename; + } + filename = contentList[index + 1].filename; + emit btnVideoClicked(filename); + QString h = filename.mid(8, 2); + QString m = filename.mid(10, 2); + QString s = filename.mid(12, 2); + QString str = QString("%1:%2:%3").arg(h).arg(m).arg(s); + // 选中要播放的按钮 + QList btns = ui->scrollArea->findChildren(); + for (QPushButton* btn : btns) { + if (btn->text() == str) { + btn->setChecked(true); + } + } +} + +/** + * @brief 遍历当前窗体可以获取焦点的所有控件 + */ +QList Menu::getAllFocusabelWidget() +{ + QList list = findChildren(); + QList result; + for (int i = 0; i < list.length(); i++) { + QWidget* w = list.at(i); + if (w->focusPolicy() == Qt::NoFocus || !w->isVisible()) + continue; + else { + result.push_back(w); + } + } + return result; +} diff --git a/Menu.h b/Menu.h index 3e13ce2..82be039 100755 --- a/Menu.h +++ b/Menu.h @@ -1,23 +1,54 @@ -#ifndef MENU_H -#define MENU_H - -#include - -namespace Ui { -class Menu; -} - -class Menu : public QWidget { - Q_OBJECT - -public: - explicit Menu(QWidget* parent = 0); - ~Menu(); - QString getCurChannel(); - void setCurChannel(QString channel); - -private: - Ui::Menu* ui; -}; - -#endif // MENU_H +#ifndef WIDGET_H +#define WIDGET_H + +#include "DatabaseManager.h" +#include "FocusWindow.h" +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class Menu; +} +QT_END_NAMESPACE + +class Menu : public QWidget, public FW::FocusWindow { + Q_OBJECT +public: + Menu(QWidget* parent = nullptr); + ~Menu(); + void show(); + void setChannelSelectVisible(bool visible); + +public slots: + void move(Direction direction); + void confirm(); + void clickVideo(QString type); + +signals: + void btnHdmi1Checked(); + void btnHdmi2Checked(); + void btnVga1Checked(); + void btnVga2Checked(); + void btnVideoClicked(QString name); + void curChannelChanged(QString channel); + +protected: + // 重写父类的方法,以获取当前界面的所有可以获取焦点的控件 + QList getAllFocusabelWidget() override; + +private: + Ui::Menu* ui; + // 视频名数组列表 + QList contentList; + DatabaseManager* db; + DatabaseManager::Channel currentChannel; + QString currentFilename; + +private: + void getContents(); + void renderContents(); + void renderComboBoxYear(); + void renderComboBoxMonth(); + void renderComboBoxDay(); +}; +#endif // WIDGET_H diff --git a/Menu.ui b/Menu.ui index 4cd7132..5cef797 100755 --- a/Menu.ui +++ b/Menu.ui @@ -1,101 +1,909 @@ - - - Menu - - - - 0 - 0 - 130 - 100 - - - - - 12 - - - - Form - - - QPushButton { - border: none; - background: rgba(0, 0, 0, 0.8); - color: #ffffff; -} - -QPushButton::checked{ - /*color: #1668dc;*/ -color:#3c89e8; -} - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 50 - - - - - 12 - - - - 视频源1 - - - true - - - true - - - - - - - - 0 - 50 - - - - - 12 - - - - 视频源2 - - - true - - - true - - - - - - - - + + + Menu + + + + 0 + 0 + 800 + 600 + + + + Widget + + + QWidget#Menu{ + background: rgba(44,44,46, 0.5); +} + +QWidget { +color: rgba(255,255,255,0.5); +font: 10pt "微软雅黑"; +} + +QPushButton { + border: none; + outline: none; +} + +QWidget:focus{ + border: 3px solid rgba(15,216,82, 0.5); +} + +QPushButton:checked { + background: rgba(94,92,230, 0.5); +} + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame#navBar{ +margin-bottom:2px; +border-bottom: 2px solid rgba(227,227,227,0.5); +} + +QPushButton { + background: rgba(100, 100, 100, 0.5); + font: 10pt "微软雅黑"; + min-height: 40px; + max-height:40px; + min-width: 100px; +} + +QPushButton:checked { + background: rgba(94,92,230,0.5); +} + + + + 0 + + + 0 + + + 10 + + + 0 + + + 10 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 100 + 40 + + + + + 16777215 + 40 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + + + + 通道设置 + + + true + + + true + + + true + + + + + + + + 100 + 40 + + + + + 16777215 + 40 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + + + + 回放 + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + + + + 1 + + + + QPushButton { +background: rgba(100,100,100, 0.5); + font: 10pt "微软雅黑"; + min-height: 60px; + min-width: 100px; + border-radius: 5px; +} + +QPushButton:checked { + background: rgba(94,92,230, 0.5); +} + +QFrame#line +{ + color:rgba(51,51,51,0.5); +} + + + + 20 + + + 10 + + + 10 + + + 10 + + + 10 + + + + + + 0 + 40 + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 微软雅黑 + 10 + 50 + false + false + + + + Qt::RightToLeft + + + 通道1: + + + + + + + + 100 + 60 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + HDMI + + + true + + + true + + + true + + + + + + + + 100 + 60 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + VGA + + + true + + + true + + + + + + + + + + + 0 + 40 + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 微软雅黑 + 10 + 50 + false + false + + + + Qt::RightToLeft + + + 通道2: + + + + + + + + 100 + 60 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + HDMI + + + true + + + true + + + true + + + + + + + + 100 + 60 + + + + + 微软雅黑 + 10 + 50 + false + false + + + + VGA + + + true + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QPushButton { + background: rgba(100,100,100,50%); + font: 10pt "微软雅黑"; +} + +QWidget:focus{ + border: 3px solid rgba(15,216,82,0.5); +} + +QPushButton:checked { + background: rgba(94,92,230,0.5); +} + + +QComboBox{ + background:rgba(255,255,255,0.5); + font: 10pt "微软雅黑"; + padding: 1px 15px 1px 3px; + border:1px solid rgba(228,228,228,0.5); + border-radius:5px 5px 0px 0px; +} + QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 15px; + border:none; + } + QComboBox QAbstractItemView{ + background:rgba(255,255,255,0.5); + border:1px solid rgba(228,228,228,0.5); + border-radius:0px 0px 5px 5px; + font-size:14px; + outline: 0px; + } +QComboBox QAbstractItemView::item{ + height:36px; + color:#666666; + padding-left:9px; + background-color:rgba(255,255,255,0.5); +} +QComboBox QAbstractItemView::item:hover{ + background-color:rgba(64,156,225,0.5); + color:#ffffff; +} +QComboBox QAbstractItemView::item:selected{ + background-color:rgba(64,156,225,0.5); + color:#ffffff; +} +QComboBox:on { + padding-top: 3px; + padding-left: 4px; + } + QComboBox::down-arrow:on { + top: 1px; + left: 1px; + } + +QScrollBar:vertical{ +width:3px; +background:transparent; +margin:0px,0px,0px,0px; +padding-top:0px; +padding-bottom:0px; +} +QScrollBar::handle:vertical +{ +width:3px; +background:rgba(69,178,255,70%); +border-radius:4px; +min-height:20 +} +QScrollBar::handle:vertical:hover{ +width:3px; +background:rgba(69,178,255,70%); +border-radius:4px; +min-height:20; +} +QScrollBar::add-line:vertical +{ +height:0px;width:4px; +subcontrol-position:bottom; +} +QScrollBar::sub-line:vertical +{ +height:0px;width:4px; +subcontrol-position:top; +} +QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical +{ +background:rgba(232,234,239,0.5); +border-radius:4px; +} + + + + 6 + + + 10 + + + 10 + + + 10 + + + 10 + + + + + 0 + + + 0 + + + + + + 7 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 通道: + + + + + + + + 100 + 40 + + + + + 16777215 + 16777215 + + + + 通道1 + + + true + + + true + + + true + + + + + + + + 100 + 40 + + + + + 16777215 + 16777215 + + + + + + + 通道2 + + + true + + + false + + + false + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 7 + + + + + 日期: + + + + + + + + 100 + 40 + + + + + 100 + 16777215 + + + + color: #000000; + + + + + + + + 100 + 40 + + + + + 100 + 16777215 + + + + color: #000000; + + + + + + + + 100 + 40 + + + + + 100 + 16777215 + + + + color: #000000; + + + + + + + + 100 + 40 + + + + + 16777215 + 16777215 + + + + 确认 + + + true + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::NoFocus + + + QScrollArea { + background-color:rgba(25, 25, 25, 0.5); +} + +QScrollBar:vertical{ +width:8px; +background:transparent; +margin:0px,0px,0px,0px; +padding-top:0px; +padding-bottom:0px; +} +QScrollBar::handle:vertical +{ +width:8px; +background:rgba(69,178,255,70%); +border-radius:4px; +min-height:20 +} +QScrollBar::handle:vertical:hover{ +width:8px; +background:rgba(69,178,255,70%); +border-radius:4px; +min-height:20; +} +QScrollBar::add-line:vertical +{ +height:0px;width:8px; +subcontrol-position:bottom; +} +QScrollBar::sub-line:vertical +{ +height:0px;width:8px; +subcontrol-position:top; +} +QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical +{ +background:rgba(232,234,239,0.5); +border-radius:4px; +} + + + true + + + + + 0 + 0 + 776 + 416 + + + + QWidget#scrollAreaWidgetContents { + background: rgba(25, 25, 25, 0.5); + border: none; +} + + + + + + + + + + + + + + + + + diff --git a/ProgressBar.cpp b/ProgressBar.cpp index 6109592..31a083c 100755 --- a/ProgressBar.cpp +++ b/ProgressBar.cpp @@ -69,7 +69,7 @@ void ProgressBar::setDuration(int dur) { this->duration = dur; ui->horizontalSlider->setMaximum(dur); - QString time = this->secToString(dur); + QString time = this->msecToString(dur); this->durationStr = time; ui->label->setText(QString("00:00:00/%1").arg(time)); } @@ -77,7 +77,7 @@ void ProgressBar::setDuration(int dur) void ProgressBar::setCurrent(int cur) { ui->horizontalSlider->setValue(cur); - QString time = this->secToString(cur); + QString time = this->msecToString(cur); ui->label->setText(QString("%1/%2").arg(time).arg(durationStr)); } diff --git a/ProgressBar.h b/ProgressBar.h index 9b2c47b..70991b0 100755 --- a/ProgressBar.h +++ b/ProgressBar.h @@ -1,6 +1,7 @@ #ifndef PROGRESSBAR_H #define PROGRESSBAR_H +#include #include #include #include @@ -23,7 +24,7 @@ public: void setDuration(int dur); void setCurrent(int cur); void setState(PlayState state); - inline QString secToString(int msc); + inline QString msecToString(int msc); private slots: void onTimeout(); @@ -40,9 +41,10 @@ private: QString sliderMinStyles; }; -inline QString ProgressBar::secToString(int msc) +inline QString ProgressBar::msecToString(int msc) { - QString formatStr = QTime(0, 0, 0).addSecs(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; } diff --git a/ProgressBar.ui b/ProgressBar.ui index b0d0539..abc7643 100755 --- a/ProgressBar.ui +++ b/ProgressBar.ui @@ -13,6 +13,9 @@ Form + + + 0 @@ -57,6 +60,9 @@ + + 999999999 + Qt::Horizontal diff --git a/RecordControlApplication.pro b/RecordControlApplication.pro index 9c81698..fecb16e 100755 --- a/RecordControlApplication.pro +++ b/RecordControlApplication.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui network serialport +QT += core gui network serialport sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -45,7 +45,8 @@ SOURCES += \ TcpRequestHandler.cpp \ TcpResponse.cpp \ SerialPortTool.cpp \ - ChannelSetting.cpp + FocusWindow.cpp \ + DatabaseManager.cpp HEADERS += \ Widget.h \ @@ -62,13 +63,13 @@ HEADERS += \ TcpRequestHandler.h \ TcpResponse.h \ SerialPortTool.h \ - ChannelSetting.h + FocusWindow.h \ + DatabaseManager.h FORMS += \ Menu.ui \ ProgressBar.ui \ - Widget.ui \ - ChannelSetting.ui + Widget.ui RESOURCES += \ res.qrc diff --git a/SerialPortTool.cpp b/SerialPortTool.cpp index 797e89e..0abea12 100644 --- a/SerialPortTool.cpp +++ b/SerialPortTool.cpp @@ -106,10 +106,10 @@ void SerialPortTool::onTimeout() timer->stop(); bool ret = serialPort->open(QIODevice::ReadWrite); if (!ret) { - Log::info("reopen serial port: /dev/ttyAMA2 success"); + Log::error("reopen serial port: /dev/ttyAMA2 failed, ready to retry..."); timer->start(); } else { - Log::error("reopen serial port: /dev/ttyAMA2 failed, ready to retry..."); + Log::info("reopen serial port: /dev/ttyAMA2 success"); } } @@ -126,7 +126,7 @@ void SerialPortTool::onReayRead() // 当发送数据频率很大时,可以使用另外的缓冲区来存储读到的数据,然后读取缓冲区的数据进行指令的解析 // 将缓冲区的数据全部读取出来 QByteArray data = serialPort->readAll(); - qDebug() << "data:" << data; + qDebug() << "receive command:" << data; // 对接受的数据进行协议解析 // 查找包头和包尾 @@ -155,31 +155,32 @@ void SerialPortTool::onReayRead() switch (frame[4]) { case 1: - emit btnPlaybackClicked(); + // 菜单 + emit btnMenuClicked(); break; case 2: - emit btnPreviousClicked(); + // 上 + emit btnUpClicked(); break; case 3: - emit btnPauseClicked(); + // 下 + emit btnDownClicked(); break; case 4: - emit btnReturnClicked(); + // 左 + emit btnLeftClicked(); break; case 5: - emit btnBackClicked(); + // 右 + emit btnRightClicked(); break; case 6: - emit btnNextClicked(); + // 确认 + emit btnConfirmClicked(); break; case 7: - emit btnForwardClicked(); - break; - case 8: - emit btnDoneClicked(); - break; - case 9: - emit btnChannelSettingClicked(); + // 返回 + emit btnReturnClicked(); break; default: break; @@ -300,24 +301,28 @@ void SerialPortTool::onSecondaryChannelOff() void SerialPortTool::onMainChannelHDMI() { + qDebug() << "main channel hdmi:" << cmdMap.value(MainChannelHDMI); serialPort->write(cmdMap.value(MainChannelHDMI)); serialPort->flush(); } void SerialPortTool::onMainChannelVGA() { + qDebug() << "main channel vga:" << cmdMap.value(MainChannelVGA); serialPort->write(cmdMap.value(MainChannelVGA)); serialPort->flush(); } void SerialPortTool::onSecondaryChannelHDMI() { + qDebug() << "secondary channel hdmi:" << cmdMap.value(SecondaryChannelHDMI); serialPort->write(cmdMap.value(SecondaryChannelHDMI)); serialPort->flush(); } void SerialPortTool::onSecondaryChannelVGA() { + qDebug() << "secondary channel vga:" << cmdMap.value(SecondaryChanneVGA); serialPort->write(cmdMap.value(SecondaryChanneVGA)); serialPort->flush(); } diff --git a/SerialPortTool.cpp.bak b/SerialPortTool.cpp.bak new file mode 100644 index 0000000..5a10437 --- /dev/null +++ b/SerialPortTool.cpp.bak @@ -0,0 +1,327 @@ +#include "SerialPortTool.h" +#include "Log.h" + +SerialPortTool::SerialPortTool(QObject* parent) + : QObject(parent) +{ + + serialPort = new QSerialPort(); + connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReayRead())); + connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onSerialError(QSerialPort::SerialPortError))); + + timer = new QTimer(); + timer->setInterval(3000); + timer->stop(); + connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout())); + + auto makeCommand = [=](int type, QString data, QString enable) { + // 命令类型 + QString t; + if (type == 2) + t = "02"; // 指示灯 + else + t = "03"; // 使能 + return QByteArray::fromHex(QString("A2 B2 08 %1 %2 %3 C2 D2") + .arg(t) + .arg(data) + .arg(enable) + .toLatin1()); + }; + + cmdMap[Reset] = makeCommand(2, "00", "00"); + cmdMap[PlaybackStart] = makeCommand(2, "01", "01"); + cmdMap[PlaybackEnd] = makeCommand(2, "01", "00"); + cmdMap[RecordStart] = makeCommand(2, "02", "01"); + cmdMap[RecordEnd] = makeCommand(2, "02", "00"); + cmdMap[PlayPause] = makeCommand(2, "03", "01"); + cmdMap[PlayResume] = makeCommand(2, "03", "00"); + cmdMap[DiskWillFull] = makeCommand(2, "04", "01"); + cmdMap[DiskNotFull] = makeCommand(2, "04", "00"); + cmdMap[PowerOn] = makeCommand(2, "05", "01"); + cmdMap[PowerOff] = makeCommand(2, "05", "00"); + cmdMap[Forward] = makeCommand(2, "08", "01"); + cmdMap[LoopOn] = makeCommand(2, "07", "01"); + cmdMap[LoopOff] = makeCommand(2, "07", "00"); + cmdMap[Back] = makeCommand(2, "06", "01"); + cmdMap[MainChannelOn] = makeCommand(2, "09", "01"); + cmdMap[MainChannelOff] = makeCommand(2, "09", "00"); + cmdMap[SecondaryChannelOn] = makeCommand(2, "0A", "01"); + cmdMap[SecondaryChannelOff] = makeCommand(2, "0A", "00"); + cmdMap[MainChannelHDMI] = makeCommand(3, "03", "00"); + cmdMap[MainChannelVGA] = makeCommand(3, "03", "01"); + cmdMap[SecondaryChannelHDMI] = makeCommand(3, "04", "00"); + cmdMap[SecondaryChanneVGA] = makeCommand(3, "04", "01"); +} + +SerialPortTool::~SerialPortTool() +{ + serialPort->close(); + delete serialPort; +} + +/** + * @brief 打开串口 + */ +void SerialPortTool::open() +{ + serialPort->setPortName("ttyAMA2"); + serialPort->setBaudRate(QSerialPort::Baud115200); + serialPort->setDataBits(QSerialPort::Data8); + serialPort->setParity(QSerialPort::NoParity); + serialPort->setStopBits(QSerialPort::OneStop); + serialPort->setFlowControl(QSerialPort::NoFlowControl); + if (serialPort->open(QIODevice::ReadWrite)) { + Log::info("open serial port: /dev/ttyAMA2 success"); + } else { + Log::error("open serial port: /dev/ttyAMA2 failed, ready to retry..."); + timer->start(); + } +} + +/** + * @brief 关闭串口 + */ +void SerialPortTool::close() +{ + serialPort->close(); +} + +/** + * @brief 串口报错槽函数 + */ +void SerialPortTool::onSerialError(QSerialPort::SerialPortError error) +{ + if (error == QSerialPort::ResourceError) { + Log::error("serial port break, try to reopen"); + serialPort->close(); + timer->start(); + } +} + +/** + * @brief 重连串口 + */ +void SerialPortTool::onTimeout() +{ + timer->stop(); + bool ret = serialPort->open(QIODevice::ReadWrite); + if (!ret) { + Log::error("reopen serial port: /dev/ttyAMA2 failed, ready to retry..."); + timer->start(); + } else { + Log::info("reopen serial port: /dev/ttyAMA2 success"); + } +} + +/** + * @brief 读取并处理收到的串口指令 + */ +void SerialPortTool::onReayRead() +{ + // 当缓冲区中有大于8个字节的数据时才处理 + if (serialPort->bytesAvailable() < 8) + return; + + // 由于本项目串口的数据频率小,可以将全部读到的数据当做一条指令来解析 + // 当发送数据频率很大时,可以使用另外的缓冲区来存储读到的数据,然后读取缓冲区的数据进行指令的解析 + // 将缓冲区的数据全部读取出来 + QByteArray data = serialPort->readAll(); + qDebug() << "receive command:" << data; + // 对接受的数据进行协议解析 + + // 查找包头和包尾 + QByteArray head = QByteArray::fromHex("A2 B2"); + QByteArray tail = QByteArray::fromHex("C2 D2"); + //... 0xA2 0xB2 0x08 0x01 0x01 0x00 0xC2 0xD2 ... + // || || + // indexHead indexTail + int indexHead = data.indexOf(head); + int indexTail = data.indexOf(tail); + // 没有查找到包头和包尾 + if (indexHead == -1 || indexTail == -1) + return; + + // 从接收的数据中截取出一帧数据 + QByteArray frame = data.mid(indexHead, indexTail + 2 - indexHead); + if (frame.length() <= 4) + return; + // 对一帧数据进行校验 + // 长度校验不通过 + if (frame[2] != frame.length()) + return; + // 命令类型 + if (data.at(3) != 0x01) + return; + + switch (frame[4]) { + case 1: + emit btnPlaybackClicked(); + break; + case 2: + emit btnPreviousClicked(); + break; + case 3: + emit btnPauseClicked(); + break; + case 4: + emit btnReturnClicked(); + break; + case 5: + emit btnBackClicked(); + break; + case 6: + emit btnNextClicked(); + break; + case 7: + emit btnForwardClicked(); + break; + case 8: + emit btnDoneClicked(); + break; + case 9: + emit btnChannelSettingClicked(); + break; + default: + break; + } +} + +void SerialPortTool::onReset() +{ + serialPort->write(cmdMap.value(Reset)); + serialPort->flush(); +} + +void SerialPortTool::onPlaybackStart() +{ + serialPort->write(cmdMap.value(PlaybackStart)); + serialPort->flush(); +} + +void SerialPortTool::onPlaybackEnd() +{ + serialPort->write(cmdMap.value(PlaybackEnd)); + serialPort->flush(); +} + +void SerialPortTool::onRecordStart() +{ + serialPort->write(cmdMap.value(RecordStart)); + serialPort->flush(); +} + +void SerialPortTool::onRecordEnd() +{ + serialPort->write(cmdMap.value(RecordEnd)); + serialPort->flush(); +} + +void SerialPortTool::onPlayPause() +{ + serialPort->write(cmdMap.value(PlayPause)); + serialPort->flush(); +} + +void SerialPortTool::onPlayResume() +{ + serialPort->write(cmdMap.value(PlayResume)); + serialPort->flush(); +} + +void SerialPortTool::onDiskWillFull() +{ + serialPort->write(cmdMap.value(DiskWillFull)); + serialPort->flush(); +} + +void SerialPortTool::onDiskNotFull() +{ + serialPort->write(cmdMap.value(DiskNotFull)); + serialPort->flush(); +} +void SerialPortTool::onPowerOn() +{ + serialPort->write(cmdMap.value(PowerOn)); + serialPort->flush(); +} +void SerialPortTool::onPowerOff() +{ + serialPort->write(cmdMap.value(PowerOff)); + serialPort->flush(); +} + +void SerialPortTool::onFoward() +{ + serialPort->write(cmdMap.value(Forward)); + serialPort->flush(); +} + +void SerialPortTool::onBack() +{ + serialPort->write(cmdMap.value(Back)); + serialPort->flush(); +} + +void SerialPortTool::onLoopOn() +{ + serialPort->write(cmdMap.value(LoopOn)); + serialPort->flush(); +} + +void SerialPortTool::onLoopOff() +{ + serialPort->write(cmdMap.value(LoopOff)); + serialPort->flush(); +} + +void SerialPortTool::onMainChannelOn() +{ + serialPort->write(cmdMap.value(MainChannelOn)); + serialPort->flush(); +} + +void SerialPortTool::onMainChannelOff() +{ + serialPort->write(cmdMap.value(MainChannelOff)); + serialPort->flush(); +} + +void SerialPortTool::onSecondaryChannelOn() +{ + serialPort->write(cmdMap.value(SecondaryChannelOn)); + serialPort->flush(); +} + +void SerialPortTool::onSecondaryChannelOff() +{ + serialPort->write(cmdMap.value(SecondaryChannelOff)); + serialPort->flush(); +} + +void SerialPortTool::onMainChannelHDMI() +{ + qDebug() << "main channel hdmi:" << cmdMap.value(MainChannelHDMI); + serialPort->write(cmdMap.value(MainChannelHDMI)); + serialPort->flush(); +} + +void SerialPortTool::onMainChannelVGA() +{ + qDebug() << "main channel vga:" << cmdMap.value(MainChannelVGA); + serialPort->write(cmdMap.value(MainChannelVGA)); + serialPort->flush(); +} + +void SerialPortTool::onSecondaryChannelHDMI() +{ + qDebug() << "secondary channel hdmi:" << cmdMap.value(SecondaryChannelHDMI); + serialPort->write(cmdMap.value(SecondaryChannelHDMI)); + serialPort->flush(); +} + +void SerialPortTool::onSecondaryChannelVGA() +{ + qDebug() << "secondary channel vga:" << cmdMap.value(SecondaryChanneVGA); + serialPort->write(cmdMap.value(SecondaryChanneVGA)); + serialPort->flush(); +} diff --git a/SerialPortTool.h b/SerialPortTool.h index 870a4af..9b73989 100644 --- a/SerialPortTool.h +++ b/SerialPortTool.h @@ -42,16 +42,15 @@ private slots: void onSerialError(QSerialPort::SerialPortError error); void onTimeout(); void onReayRead(); + signals: - void btnPlaybackClicked(); - void btnPreviousClicked(); - void btnPauseClicked(); + void btnMenuClicked(); + void btnUpClicked(); + void btnDownClicked(); + void btnLeftClicked(); + void btnRightClicked(); + void btnConfirmClicked(); void btnReturnClicked(); - void btnBackClicked(); - void btnNextClicked(); - void btnForwardClicked(); - void btnDoneClicked(); - void btnChannelSettingClicked(); private: enum CommandType { diff --git a/SerialPortTool.h.bak b/SerialPortTool.h.bak new file mode 100644 index 0000000..870a4af --- /dev/null +++ b/SerialPortTool.h.bak @@ -0,0 +1,88 @@ +#ifndef SERIALPORT_H +#define SERIALPORT_H +#include +#include +#include +#include + +class SerialPortTool : public QObject { + Q_OBJECT + +public: + explicit SerialPortTool(QObject* parent = 0); + ~SerialPortTool(); + void open(); + void close(); +public slots: + void onReset(); + void onPlaybackStart(); + void onPlaybackEnd(); + void onRecordStart(); + void onRecordEnd(); + void onPlayPause(); + void onPlayResume(); + void onDiskWillFull(); + void onDiskNotFull(); + void onPowerOn(); + void onPowerOff(); + void onFoward(); + void onBack(); + void onLoopOn(); + void onLoopOff(); + void onMainChannelOn(); + void onMainChannelOff(); + void onSecondaryChannelOn(); + void onSecondaryChannelOff(); + void onMainChannelHDMI(); + void onMainChannelVGA(); + void onSecondaryChannelHDMI(); + void onSecondaryChannelVGA(); + +private slots: + void onSerialError(QSerialPort::SerialPortError error); + void onTimeout(); + void onReayRead(); +signals: + void btnPlaybackClicked(); + void btnPreviousClicked(); + void btnPauseClicked(); + void btnReturnClicked(); + void btnBackClicked(); + void btnNextClicked(); + void btnForwardClicked(); + void btnDoneClicked(); + void btnChannelSettingClicked(); + +private: + enum CommandType { + Reset, + PlaybackStart, + PlaybackEnd, + RecordStart, + RecordEnd, + PlayPause, + PlayResume, + DiskWillFull, + DiskNotFull, + PowerOn, + PowerOff, + Forward, + Back, + LoopOn, + LoopOff, + MainChannelOn, + MainChannelOff, + SecondaryChannelOff, + SecondaryChannelOn, + MainChannelHDMI, + MainChannelVGA, + SecondaryChannelHDMI, + SecondaryChanneVGA + }; + + QSerialPort* serialPort; // 串口 + QMap cmdMap; // 指令列表 + QTimer* timer; +}; + +#endif // SERIALPORT_H diff --git a/TcpRequestHandler.cpp b/TcpRequestHandler.cpp index cc3db73..b297c01 100755 --- a/TcpRequestHandler.cpp +++ b/TcpRequestHandler.cpp @@ -1,6 +1,7 @@ #include "TcpRequestHandler.h" #include "Channel.h" #include "Constant.h" +#include "DatabaseManager.h" #include "Json.h" #include "Log.h" #include "Tool.h" @@ -8,6 +9,7 @@ #include extern const QList channelList; +extern DatabaseManager* db; TcpRequestHandler::TcpRequestHandler(QObject* parent) : QObject(parent) @@ -180,21 +182,21 @@ void TcpRequestHandler::getVideoEnc(TcpRequest* request, TcpResponse* reponse) void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse) { QVariantMap params = request->getBodyParams(); - if (params.isEmpty() || !params.contains("interface")) { - Log::error("getFileList params error, missing param \"interface\""); - reponse->error("缺少接口参数"); + QString chn = params.value("interface").toString(); + if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) { + Log::error("getFileList params error, error param \"interface\""); + reponse->error("接口参数错误"); return; } - + DatabaseManager::Channel channel = chn == Constant::MainChannel ? DatabaseManager::MainChannel + : DatabaseManager::SecondaryChannel; QString interface = params.value("interface").toString(); - QString videoPath = QString("%1/%2").arg(Constant::VideoPath).arg(interface); - - QStringList videoList = Tool::getFileList(videoPath); - // 如果最后一个文件名是当前正在录制的文件名,则去除 - if (videoList.last() == Channel::curRecordFilename) { - videoList.pop_back(); + QList fileList = db->get(channel); + QStringList result; + for (const DatabaseManager::File& file : fileList) { + result.push_back(file.filename); } - reponse->success("获取文件成功", videoList); + reponse->success("获取文件成功", result); } /** @@ -204,18 +206,25 @@ void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse) void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse) { QVariantMap params = request->getBodyParams(); - if (!params.contains("interface") || !params.contains("filename")) { - Log::error("deleteFile params error, missing params \"interface\" or \"filename\""); - reponse->error("缺少端口或文件名"); + QString chn = params.value("interface").toString(); + QString filename = params.value("filename").toString(); + if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) { + Log::error("deleteFile params error, error params \"interface\" or \"filename\""); + reponse->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(Constant::VideoPath).arg(interface).arg(fileName); + if (filename.isEmpty()) { + Log::error("deleteFile params error, missing params \"filename\""); + reponse->error("缺少文件名参数"); + 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); QFile video(filePath); if (video.exists()) { video.remove(); @@ -334,4 +343,4 @@ void TcpRequestHandler::setCurrentTime(TcpRequest* request, TcpResponse* reponse } else { reponse->success("时间同步成功"); } -} \ No newline at end of file +} diff --git a/Tool.cpp b/Tool.cpp index 0ad1e1c..c1cba9f 100755 --- a/Tool.cpp +++ b/Tool.cpp @@ -1,6 +1,7 @@ #include "Tool.h" #include #include +#include #include #include @@ -121,3 +122,18 @@ int64_t Tool::getAvailableStorage(QString mountedPath) return 0; #endif } + +/** + * @brief 获取代码块运行的时间 + * @param callback + * @return + */ +double Tool::getCostTime(std::function callback, const char* callbackName) +{ + QElapsedTimer mstimer; + mstimer.start(); + callback(); + double time = (double)mstimer.nsecsElapsed() / (double)1000000; + qDebug() << callbackName << "cast time:" << time << "ms"; + return time; +} diff --git a/Tool.h b/Tool.h index f521e6b..d427a01 100755 --- a/Tool.h +++ b/Tool.h @@ -1,17 +1,22 @@ #ifndef TOOL_H #define TOOL_H #include +#include class Tool { public: Tool(); static QStringList getFileList(QString path); + static bool removeFile(QString path); + #ifdef Q_OS_LINUX static QString writeCom(QString path); #endif static int64_t getAvailableStorage(QString mountedPath); + + static double getCostTime(std::function callback, const char* callbackName = ""); }; #endif // TOOL_H diff --git a/Widget.cpp b/Widget.cpp index be32b40..40b8f6d 100755 --- a/Widget.cpp +++ b/Widget.cpp @@ -26,32 +26,21 @@ Widget::Widget(QWidget* parent) , ui(new Ui::Widget) { ui->setupUi(this); - ui->lblA->setPixmap(QPixmap(":/images/no-record.png")); - ui->lblB->setPixmap(QPixmap(":/images/no-record.png")); + ui->lblImgA->setPixmap(QPixmap(":/images/no-record.png")); + ui->lblImgB->setPixmap(QPixmap(":/images/no-record.png")); + ui->lblTxtA->setText("未录制"); + ui->lblTxtB->setText("未录制"); + ui->recordWidget->hide(); - menu = new Menu(this); + menu = new Menu(); menu->hide(); - - progressBar = new ProgressBar(this); - progressBar->hide(); - - channelSetting = new ChannelSetting(this); - channelSetting->hide(); - - // 设置窗体背景透明 - QPalette pal = palette(); - pal.setBrush(QPalette::Base, Qt::transparent); - setPalette(pal); - setAttribute(Qt::WA_TranslucentBackground, true); - - // 设置listwidget无滚动条 - ui->listWidget->horizontalScrollBar()->hide(); - ui->listWidget->verticalScrollBar()->hide(); - ui->listWidget->hide(); + // 设置是否显示通道选择 + menu->setChannelSelectVisible(playbackMode == Constant::OneChannelPlayback); + ui->progressBar->hide(); // 每5秒更新一次进度条 progressTimer = new QTimer(); - progressTimer->setInterval(500); + progressTimer->setInterval(200); connect(progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimeout())); for (Channel* chn : channelList) { @@ -63,8 +52,7 @@ Widget::Widget(QWidget* parent) QVariantMap data = msg.toMap(); bool available = data["avalible"].toBool(); if (available) { - Log::info("video input {} is available", - chn->channelName == Constant::MainChannel ? "HDMI-C" : "HDMI-D"); + Log::info("video input {} is available", chn->channelName == Constant::MainChannel ? Constant::MainChannel : Constant::SecondaryChannel); if (chn->channelName == Constant::MainChannel) { serialPortTool->onMainChannelOn(); QThread::msleep(100); @@ -73,8 +61,7 @@ Widget::Widget(QWidget* parent) QThread::msleep(100); } } else { - Log::info("video input {} is not available", - chn->channelName == Constant::MainChannel ? "HDMI-C" : "HDMI-D"); + Log::info("video input {} is not available", chn->channelName == Constant::MainChannel ? Constant::MainChannel : Constant::SecondaryChannel); if (chn->channelName == Constant::MainChannel) { serialPortTool->onMainChannelOff(); QThread::msleep(100); @@ -87,15 +74,17 @@ Widget::Widget(QWidget* parent) }); } - connect(serialPortTool, SIGNAL(btnPlaybackClicked()), this, SLOT(onBtnPlaybackClicked())); - connect(serialPortTool, SIGNAL(btnPreviousClicked()), this, SLOT(onBtnPreviousClicked())); - connect(serialPortTool, SIGNAL(btnPauseClicked()), this, SLOT(onBtnPasueClicked())); + connect(serialPortTool, SIGNAL(btnMenuClicked()), this, SLOT(onBtnMenuClicked())); + connect(serialPortTool, SIGNAL(btnUpClicked()), this, SLOT(onBtnUpClicked())); + connect(serialPortTool, SIGNAL(btnDownClicked()), this, SLOT(onBtnDownClicked())); + connect(serialPortTool, SIGNAL(btnLeftClicked()), this, SLOT(onBtnLeftClicked())); + connect(serialPortTool, SIGNAL(btnRightClicked()), this, SLOT(onBtnRightClicked())); + connect(serialPortTool, SIGNAL(btnConfirmClicked()), this, SLOT(onBtnConfirmClicked())); connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked())); - connect(serialPortTool, SIGNAL(btnBackClicked()), this, SLOT(onBtnBackClicked())); - connect(serialPortTool, SIGNAL(btnNextClicked()), this, SLOT(onBtnNextClicked())); - connect(serialPortTool, SIGNAL(btnForwardClicked()), this, SLOT(onBtnForwardClicked())); - connect(serialPortTool, SIGNAL(btnDoneClicked()), this, SLOT(onBtnEnterClicked())); - connect(serialPortTool, SIGNAL(btnChannelSettingClicked()), this, SLOT(onBtnChannelSettingClicked())); + + connect(menu, SIGNAL(curChannelChanged(QString)), this, SLOT(onCurChannelChanged(QString))); + connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString))); + connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickVideo(QString))); } Widget::~Widget() @@ -103,57 +92,6 @@ Widget::~Widget() delete ui; delete progressTimer; delete menu; - delete progressBar; - delete channelSetting; -} - -void Widget::renderList() -{ - ui->listWidget->clear(); - if (fileList.isEmpty()) { - ui->listWidget->show(); - return; - } - // 如果在录制中应该出去正在录制的文件名 - if (fileList.last() == Channel::curRecordFilename) { - fileList.pop_back(); - } - - QListWidgetItem* curItem = nullptr; - for (QString& file : fileList) { - QListWidgetItem* item = new QListWidgetItem(file); - ui->listWidget->addItem(item); - if (isPlayback) { - // 一路回放 - if (playbackMode == Constant::OneChannelPlayback) { - if (curPlayChannel == curSelectChannel && item->text() == curPlayFilename) { - curItem = item; - } - } - // 两路回放 - else { - if (item->text() == curPlayFilename) { - curItem = item; - } - } - } - } - ui->listWidget->show(); - if (curItem) { - ui->listWidget->setCurrentItem(curItem); - } else { - ui->listWidget->setCurrentRow(0); - } -} - -/** - * @brief 获取视频文件列表并显示 - */ -void Widget::showPlayList() -{ - QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curSelectChannel); - fileList = Tool::getFileList(dirPath); - renderList(); } /** @@ -162,153 +100,34 @@ void Widget::showPlayList() void Widget::onProgressTimeout() { Channel* chn = findChannelByName(Constant::MainChannel); - int pos = chn->file->invoke("getPosition").toInt() / 1000; - progressBar->setCurrent(pos); + if (chn) { + // 获取当前播放位置,单位ms + int pos = chn->inputFile->invoke("getPosition").toInt(); + ui->progressBar->setCurrent(pos); + } } /** - * @brief 收到回放指令 + * @brief 按下菜单按键 */ -void Widget::onBtnPlaybackClicked() +void Widget::onBtnMenuClicked() { - // 如果在进行通道设置屏蔽回放操作 - if (channelSetting->isVisible()) - return; - Log::info("receive command playback, playback mode: {}", playbackMode); - // 如果是一路回放,显示选择菜单 - if (playbackMode == Constant::OneChannelPlayback) { - if (!menu->isVisible()) - menu->show(); - } - // 两路回放不显示菜单,直接显示列表 - else if (playbackMode == Constant::TwoChannelPlayback) { - curSelectChannel = Constant::MainChannel; - showPlayList(); + if (!menu->isVisible()) { + menu->show(); } } /** - * @brief 收到上段指令, 优先级 - * 处理优先级: 通道设置菜单 ==> 通道选择菜单 ==> 列表 - */ -void Widget::onBtnPreviousClicked() -{ - if (channelSetting->isVisible()) { - channelSetting->onReceivePre(); - return; - } - // 菜单显示则切换菜单选中 - if (menu->isVisible()) { - menu->setCurChannel(Constant::MainChannel); - return; - } - // 列表显示,则选中上一个视频 - if (ui->listWidget->isVisible()) { - int curRow = ui->listWidget->currentRow(); - if (curRow == 0) - curRow = ui->listWidget->count(); - ui->listWidget->setCurrentRow(curRow - 1); - return; - } -} - -/** - * @brief 收到下段指令 - * 处理优先级: 通道设置菜单 ==> 通道选择菜单 ==> 列表 - */ -void Widget::onBtnNextClicked() -{ - if (channelSetting->isVisible()) { - channelSetting->onReceiveNext(); - return; - } - if (menu->isVisible()) { - menu->setCurChannel(Constant::SecondaryChannel); - return; - } - if (ui->listWidget->isVisible()) { - int curRow = ui->listWidget->currentRow(); - if (curRow == ui->listWidget->count() - 1) { - curRow = -1; - } - ui->listWidget->setCurrentRow(curRow + 1); - return; - } -} - -/** - * @brief 收到暂停指令 - */ -void Widget::onBtnPasueClicked() -{ - if (!isPlayback) - return; - for (Channel* chn : channelList) { - if (chn->state == Channel::Playback || chn->state == Channel::Pause) { - chn->togglePause(); - if (chn->channelName == Constant::MainChannel) { - progressBar->showMax(); - if (chn->state == Channel::Pause) { - progressBar->setState(ProgressBar::Pause); - // 打开暂停灯 - serialPortTool->onPlayPause(); - } else { - progressBar->setState(ProgressBar::Play); - // 关闭暂停灯 - serialPortTool->onPlayResume(); - } - } - } - } -} - -/** - * @brief 收到确定指令 - * 通道设置菜单 ==> 通道选择菜单 ==> 列表 - */ -void Widget::onBtnEnterClicked() -{ - if (channelSetting->isVisible()) { - channelSetting->onReceiveEnter(); - return; - } - // 菜单显示,则关闭菜单显示列表 - if (menu->isVisible()) { - curSelectChannel = menu->getCurChannel(); - menu->hide(); - showPlayList(); - return; - } - if (ui->listWidget->isVisible()) { - if (ui->listWidget->count() == 0) - return; - if (playbackMode == Constant::OneChannelPlayback) - playOneChannel(); - else if (playbackMode == Constant::TwoChannelPlayback) - playTwoChannels(); - serialPortTool->onPlaybackStart(); - return; - } -} - -/** - * @brief 收到返回指令 - * 处理优先级: 通道设置菜单 ==> 通道选择菜单 ==> 列表 ==> 回放 + * @brief 按下返回按键。优先级:菜单 > 播放 */ void Widget::onBtnReturnClicked() { - if (channelSetting->isVisible()) { - channelSetting->hide(); - return; - } + // 关闭菜单 if (menu->isVisible()) { menu->hide(); return; } - if (ui->listWidget->isVisible()) { - ui->listWidget->hide(); - return; - } + // 关闭回放 if (isPlayback) { // 停止回放 for (Channel* chn : channelList) { @@ -318,12 +137,215 @@ void Widget::onBtnReturnClicked() curPlayFilename = ""; } } - progressBar->hide(); - ui->lblA->show(); - ui->lblB->show(); + // 隐藏进度条并关闭定时器 + ui->progressBar->hide(); + progressTimer->stop(); + // 显示录制状态 + // ui->recordWidget->show(); } } +/** + * @brief 按下上键。优先级: 菜单 > 播放 + */ +void Widget::onBtnUpClicked() +{ + if (menu->isVisible()) { + menu->move(Menu::Up); + return; + } + if (isPlayback) { + emit needPlayVideo("previous"); + } +} + +/** + * @brief 按下下键。 优先级: 菜单 > 播放 + */ +void Widget::onBtnDownClicked() +{ + if (menu->isVisible()) { + menu->move(Menu::Down); + return; + } + if (isPlayback) { + emit needPlayVideo("next"); + } +} + +/** + * @brief 按下左键。优先级: 菜单 > 播放。 + */ +void Widget::onBtnLeftClicked() +{ + if (menu->isVisible()) { + menu->move(Menu::Left); + return; + } + if (isPlayback) { + seek("back"); + } +} + +/** + * @brief 按下左键。优先级: 菜单 > 播放 + */ +void Widget::onBtnRightClicked() +{ + if (menu->isVisible()) { + menu->move(Menu::Right); + return; + } + if (isPlayback) { + seek("forward"); + } +} + +/** + * @brief 按下ok键。优先级: 菜单 > 回放 + */ +void Widget::onBtnConfirmClicked() +{ + if (menu->isVisible()) { + menu->confirm(); + return; + } + if (isPlayback) { + // 切换暂停和播放 + for (Channel* chn : channelList) { + if (chn->state == Channel::Playback || chn->state == Channel::Pause) { + chn->togglePause(); + if (chn->channelName == Constant::MainChannel) { + ui->progressBar->showMax(); + if (chn->state == Channel::Pause) { + ui->progressBar->setState(ProgressBar::Pause); + // 打开暂停灯 + serialPortTool->onPlayPause(); + } else { + ui->progressBar->setState(ProgressBar::Play); + // 关闭暂停灯 + serialPortTool->onPlayResume(); + } + } + } + } + } +} + +/** + * @brief 回放视频 + */ +void Widget::onBtnVideoClicked(QString filename) +{ + if (filename == "first") { + // 显示提示弹窗 + } else if (filename == "last") { + if (playbackMode == Constant::OneChannelPlayback) { + Channel* chn = findChannelByName(Constant::MainChannel); + chn->showFinishPromot(); + } else { + for (Channel* chn : channelList) + chn->showFinishPromot(); + } + } else { + if (playbackMode == Constant::OneChannelPlayback) { + playOneChannel(filename); + } else { + playTwoChannels(filename); + } + serialPortTool->onPlaybackStart(); + } +} + +void Widget::onCurChannelChanged(QString channel) +{ + curSelectChannel = channel; + Log::info("channel switch, current channel:", channel.toStdString()); +} + +/** + * @brief 一路回放,将当前选中播放的视频从HDMI-OUT0口输出 + */ +void Widget::playOneChannel(QString filename) +{ + QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curSelectChannel).arg(filename); + Channel* channel = findChannelByName(Constant::MainChannel); + for (Channel* chn : channelList) { + chn->startPlayLive(); + } + bool ret = channel->startPlayback(path); + if (!ret) { + Log::info("play back error"); + ui->progressBar->hide(); + } + + isPlayback = true; + curPlayChannel = curSelectChannel; + curPlayFilename = filename; + + // 全局保存当前播放的视频 + mutex.lock(); + curFilename = filename; + condition.wakeAll(); + mutex.unlock(); + + int duration = channel->playbackDuration; + ui->progressBar->setDuration(duration); + ui->progressBar->setCurrent(0); + ui->progressBar->show(); + ui->progressBar->showMax(); + ui->progressBar->setState(ProgressBar::Play); + + if (progressTimer->isActive()) { + progressTimer->stop(); + progressTimer->start(); + } else { + progressTimer->start(); + } + ui->recordWidget->hide(); +} + +/** + * @brief 两路回放,以主通道的视频为主分别从HDMI-OUT0和HDMI-OUT1输出 + */ +void Widget::playTwoChannels(QString filename) +{ + for (Channel* chn : channelList) { + QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(filename); + int ret = chn->startPlayback(path); + if (chn->channelName == Constant::MainChannel) { + if (ret) { + int duration = chn->playbackDuration; + ui->progressBar->setDuration(duration); + ui->progressBar->setCurrent(0); + ui->progressBar->show(); + ui->progressBar->showMax(); + ui->progressBar->setState(ProgressBar::Play); + if (progressTimer->isActive()) { + progressTimer->stop(); + progressTimer->start(); + } else { + progressTimer->start(); + } + ui->recordWidget->hide(); + } else { + ui->progressBar->hide(); + ui->recordWidget->hide(); + } + } + } + + curPlayFilename = filename; + curPlayChannel = Constant::MainChannel; + isPlayback = true; + + // 全局保存正在播放的视频 + mutex.lock(); + curFilename = filename; + condition.wakeAll(); + mutex.unlock(); +} + /** * @brief 视频跳转 */ @@ -342,133 +364,11 @@ void Widget::seek(QString type) } if (chn->channelName == Constant::MainChannel) - progressBar->showMax(); + ui->progressBar->showMax(); } } } -/** - * @brief 快进 - */ -void Widget::onBtnForwardClicked() -{ - seek("forward"); -} - -/** - * @brief 快退 - */ -void Widget::onBtnBackClicked() -{ - seek("back"); -} - -/** - * @brief 打开通道设置HDMI or VGA - */ -void Widget::onBtnChannelSettingClicked() -{ - // 关闭通道选择菜单 - if (menu->isVisible()) - menu->hide(); - // 打开通道设置菜单 - if (channelSetting->isVisible()) - return; - channelSetting->show(); -} - -/** - * @brief 一路回放,将当前选中播放的视频从HDMI-OUT0口输出 - */ -void Widget::playOneChannel() -{ - QString filename = ui->listWidget->currentItem()->text(); - QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curSelectChannel).arg(filename); - Channel* channel = findChannelByName(Constant::MainChannel); - for (Channel* chn : channelList) { - chn->startPlayLive(); - } - bool ret = channel->startPlayback(path); - if (!ret) - progressBar->hide(); - - isPlayback = true; - curPlayChannel = curSelectChannel; - curPlayFilename = filename; - - // 全局保存当前播放的视频 - mutex.lock(); - curFilename = filename; - condition.wakeAll(); - mutex.unlock(); - - // 保存当前播放视频列表 - QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curPlayChannel); - fileList = Tool::getFileList(dirPath); - - int duration = channel->playbackDuration; - progressBar->setDuration(duration); - progressBar->setCurrent(0); - progressBar->show(); - progressBar->showMax(); - progressBar->setState(ProgressBar::Play); - - if (progressTimer->isActive()) { - progressTimer->stop(); - progressTimer->start(); - } else { - progressTimer->start(); - } - ui->lblA->hide(); - ui->lblB->hide(); -} - -/** - * @brief 两路回放,以主通道的视频为主分别从HDMI-OUT0和HDMI-OUT1输出 - */ -void Widget::playTwoChannels() -{ - QString filename = ui->listWidget->currentItem()->text(); - for (Channel* chn : channelList) { - QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(filename); - int ret = chn->startPlayback(path); - if (chn->channelName == Constant::MainChannel) { - if (ret) { - int duration = chn->playbackDuration; - progressBar->setDuration(duration); - progressBar->setCurrent(0); - progressBar->show(); - progressBar->showMax(); - progressBar->setState(ProgressBar::Play); - if (progressTimer->isActive()) { - progressTimer->stop(); - progressTimer->start(); - } else { - progressTimer->start(); - } - ui->lblA->hide(); - ui->lblB->hide(); - } else { - progressBar->hide(); - } - } - } - - curPlayFilename = filename; - curPlayChannel = Constant::MainChannel; - isPlayback = true; - - // 全局保存正在播放的视频 - mutex.lock(); - curFilename = filename; - condition.wakeAll(); - mutex.unlock(); - - // 将主通道的视频列表作为主列表 - QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(Constant::MainChannel); - fileList = Tool::getFileList(dirPath); -} - /** * @brief 当前视频播放完毕 */ @@ -478,81 +378,14 @@ void Widget::onPlayEnd() if (playbackMode == Constant::TwoChannelPlayback) { LinkObject* file = static_cast(sender()); for (Channel* chn : channelList) { - if (chn->file == file) { + if (chn->inputFile == file) { if (chn->channelName != Constant::MainChannel) { return; } } } } - bool needRefresh = false; - // 计算下一个文件名 - int index = fileList.indexOf(curPlayFilename); - if (index == fileList.length() - 1) { - // 重新刷新文件列表 - QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curPlayChannel); - fileList = Tool::getFileList(dirPath); - // 刷新文件列表后还是最后一个文件 - if (index == fileList.length() - 1) { - Log::info("there is no file to play"); - // 显示播放完毕的信息 - if (playbackMode == Constant::OneChannelPlayback) { - Channel* chn = findChannelByName(Constant::MainChannel); - if (chn) - chn->showFinishPromot(); - } else if (playbackMode == Constant::TwoChannelPlayback) { - for (Channel* chn : channelList) { - chn->showFinishPromot(); - } - } - return; - } - needRefresh = true; - Log::info("refresh current play file list"); - } - curPlayFilename = fileList.at(index + 1); - - // 播放下一个视频 - if (playbackMode == Constant::OneChannelPlayback) { - Channel* chn = findChannelByName(Constant::MainChannel); - if (chn) { - QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curPlayChannel).arg(curPlayFilename); - bool ret = chn->startPlayback(path); - if (chn->channelName == Constant::MainChannel) { - if (!ret) { - progressBar->hide(); - return; - } - int duration = chn->playbackDuration; - progressBar->setDuration(duration); - progressBar->showMax(); - } - } - } else if (playbackMode == Constant::TwoChannelPlayback) { - for (Channel* chn : channelList) { - QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(curPlayFilename); - bool ret = chn->startPlayback(path); - if (chn->channelName == Constant::MainChannel) { - if (!ret) { - progressBar->hide(); - continue; - } - int duration = chn->playbackDuration; - progressBar->setDuration(duration); - progressBar->showMax(); - } - } - } - if (needRefresh) { - renderList(); - } else { - ui->listWidget->setCurrentRow(ui->listWidget->currentRow() + 1); - } - - mutex.lock(); - curFilename = curPlayFilename; - condition.wakeAll(); - mutex.unlock(); + emit needPlayVideo("next"); } /** @@ -562,16 +395,22 @@ void Widget::onPlayEnd() void Widget::onShowRecordLabel(bool show) { Channel* chn = static_cast(sender()); - QLabel* label; + QLabel* lblImg; + QLabel* lblTxt; if (chn->channelName == Constant::MainChannel) { - label = ui->lblA; + lblImg = ui->lblImgA; + lblTxt = ui->lblTxtA; } else { - label = ui->lblB; + lblImg = ui->lblImgB; + lblTxt = ui->lblTxtB; } if (show) { - label->setPixmap(QPixmap(":/images/record.png")); - } else - label->setPixmap(QPixmap(":/images/no-record.png")); + lblImg->setPixmap(QPixmap(":/images/record.png")); + lblTxt->setText("录制中"); + } else { + lblImg->setPixmap(QPixmap(":/images/no-record.png")); + lblTxt->setText("未录制"); + } } /** diff --git a/Widget.h b/Widget.h index dee8895..fdc04ec 100755 --- a/Widget.h +++ b/Widget.h @@ -2,7 +2,6 @@ #define WIDG_H #include "Channel.h" -#include "ChannelSetting.h" #include "Menu.h" #include "Message.h" #include "ProgressBar.h" @@ -21,26 +20,29 @@ public: explicit Widget(QWidget* parent = 0); ~Widget(); -public slots: - void showPlayList(); +signals: + void needPlayVideo(QString types); private slots: void onProgressTimeout(); void onPlayEnd(); void onShowRecordLabel(bool show); - void onBtnPlaybackClicked(); - void onBtnPreviousClicked(); - void onBtnNextClicked(); - void onBtnPasueClicked(); - void onBtnEnterClicked(); + + // 按键操作。上下左右确认返回 + void onBtnMenuClicked(); + void onBtnUpClicked(); + void onBtnDownClicked(); + void onBtnLeftClicked(); + void onBtnRightClicked(); + void onBtnConfirmClicked(); void onBtnReturnClicked(); - void onBtnForwardClicked(); - void onBtnBackClicked(); - void onBtnChannelSettingClicked(); + + // 播放视频 + void onBtnVideoClicked(QString filename); + void onCurChannelChanged(QString channel); private: Ui::Widget* ui; - QStringList fileList; QTimer* progressTimer; bool isPlayback = false; @@ -49,15 +51,12 @@ private: QString curPlayFilename; Menu* menu; - ProgressBar* progressBar; - ChannelSetting* channelSetting; private: void seek(QString type); - void playOneChannel(); - void playTwoChannels(); + void playOneChannel(QString filename); + void playTwoChannels(QString filename); Channel* findChannelByName(QString name); - void renderList(); }; #endif // WIDG_H diff --git a/Widget.ui b/Widget.ui index 8cb38f2..91eeabe 100755 --- a/Widget.ui +++ b/Widget.ui @@ -19,7 +19,7 @@ Widget - + background: rgba(0,0,0,0); @@ -51,48 +51,155 @@ 0 - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - 32 - 32 + 50 + 0 - - - 32 - 32 - - - - - - - :/images/record.png + + color: white; + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + :/images/record.png + + + + + + + + 10 + 50 + false + + + + color: white; + + + 录制中 + + + + + + + + + 0 + + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + :/images/record.png + + + + + + + + 10 + 50 + false + + + + color: white; + + + 1 + + + 录制中 + + + + + + - - + + + Qt::Horizontal + + - 32 - 32 + 40 + 20 - - - 32 - 32 - - - - - - - :/images/record.png - - + @@ -109,70 +216,22 @@ + + + - - - - Qt::Horizontal - - - - 1511 - 20 - - - - - - - - - 280 - 0 - - - - - 290 - 16777215 - - - - - 14 - - - - QListWidget { - color: rgba(255, 255, 255); - outline: none; - background-color: rgba(0, 0, 0, 0.4); - border: none; -} - -#listWidget::item { - - border: transparent; - padding: 6px; -} - -#listWidget::item:selected { - background-color: rgba(0, 0, 0, 0.5); - border-left: 10px solid 00AEEC; - color: #00AEEC; -} - - -QScrollBar { - width: 0; -} - - - + + + ProgressBar + QWidget +
ProgressBar.h
+ 1 +
+
diff --git a/main.cpp b/main.cpp index 29917c6..a954377 100755 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,7 @@ #include "Channel.h" #include "CheckStorageThread.h" #include "Constant.h" +#include "DatabaseManager.h" #include "Json.h" #include "Link.h" #include "Log.h" @@ -9,6 +10,7 @@ #include "Tool.h" #include "Widget.h" #include +#include #include #include @@ -16,6 +18,8 @@ TcpServer* server; // 串口工具 SerialPortTool* serialPortTool; +// 数据库管理 +DatabaseManager* db; // 视频输出通道 LinkObject* vo; LinkObject* vo1; @@ -26,6 +30,8 @@ QList channelList; Constant::RecordMode recordMode; // 回放模式 Constant::PlaybackMode playbackMode; +QString mainChannelProtocol; +QString secondaryChannelProtocol; /** * @brief 加载配置文件 @@ -47,6 +53,11 @@ bool loadConfiguration(QString path) Channel* chn = new Channel(); QVariantMap cfg = list.at(i).toMap(); chn->channelName = cfg["name"].toString(); + if (chn->channelName == Constant::MainChannel) { + mainChannelProtocol = cfg["protocol"].toString(); + } else if (chn->channelName == Constant::SecondaryChannel) { + secondaryChannelProtocol = cfg["protocol"].toString(); + } QVariantMap encV = cfg["encV"].toMap(); chn->videoEncoderParams = encV; @@ -62,15 +73,6 @@ bool loadConfiguration(QString path) return true; } -/** - * @brief 关闭所有灯光 - */ -void resetLight() -{ - printf("reset all lights"); - serialPortTool->onReset(); -} - /** * @brief 开始录制 */ @@ -84,16 +86,16 @@ void startRecord() QThread::msleep(100); return; } - + // 一路录制,只录制主通道 if (recordMode == Constant::OneChannelRecord) { for (Channel* chn : channelList) { if (chn->channelName == Constant::MainChannel) { chn->startRecord(); - QThread::msleep(100); + // QThread::msleep(100); serialPortTool->onRecordStart(); QThread::msleep(100); - serialPortTool->onLoopOff(); + // serialPortTool->onLoopOff(); } } } @@ -103,19 +105,34 @@ void startRecord() chn->startRecord(); serialPortTool->onRecordStart(); QThread::msleep(100); - serialPortTool->onLoopOff(); - QThread::msleep(100); + // serialPortTool->onLoopOff(); + // QThread::msleep(100); } } // 无录制 else { - qDebug() << "no record"; // 打开环路灯 serialPortTool->onLoopOn(); QThread::msleep(100); } } +void setChannelProtocol() +{ + if (mainChannelProtocol == "HDMI") { + serialPortTool->onMainChannelHDMI(); + } else if (mainChannelProtocol == "VGA") { + serialPortTool->onMainChannelVGA(); + } + QThread::msleep(100); + if (secondaryChannelProtocol == "HDMI") { + serialPortTool->onSecondaryChannelHDMI(); + } else if (secondaryChannelProtocol == "VGA") { + serialPortTool->onSecondaryChannelVGA(); + } + QThread::msleep(100); +} + int main(int argc, char* argv[]) { // std::atexit(resetLight); @@ -133,16 +150,15 @@ int main(int argc, char* argv[]) // HDMI-OUT0视频输出,只将ui输出在0口 vo = Link::create("OutputVo"); QVariantMap dataVo; - dataVo["vid"] = 0; + dataVo["ui"] = true; dataVo["type"] = "hdmi"; vo->start(dataVo); // HDMI-OUT1视频输出 vo1 = Link::create("OutputVo"); QVariantMap dataVo1; - dataVo1["vid"] = 1; dataVo1["ui"] = false; - dataVo1["type"] = "vga|bt1120"; + dataVo1["type"] = "bt1120"; vo1->start(dataVo1); /** @@ -152,6 +168,8 @@ int main(int argc, char* argv[]) // HDMI-OUT1口特殊设置 static int lastNorm = 0; int norm = 0; + int ddr = 0; + // 获取到设置的输出分辨率 QString str = "1080P60"; if (str == "1080P60") norm = 9; @@ -163,13 +181,15 @@ int main(int argc, char* argv[]) norm = 5; else if (str == "720P50") norm = 6; - else if (str == "3840x2160_30") + else if (str == "3840x2160_30") { norm = 14; + ddr = 1; + } if (norm != lastNorm) { lastNorm = norm; QString cmd = "rmmod hi_lt8618sx_lp.ko"; system(cmd.toLatin1().data()); - cmd = "insmod /ko/extdrv/hi_lt8618sx_lp.ko norm=" + QString::number(norm); + cmd = cmd.sprintf("insmod /ko/extdrv/hi_lt8618sx_lp.ko norm=%d USE_DDRCLK=%d", norm, ddr); system(cmd.toLatin1().data()); } @@ -185,6 +205,7 @@ int main(int argc, char* argv[]) serialPortTool = new SerialPortTool(); serialPortTool->open(); + // setChannelProtocol(); serialPortTool->onPowerOn(); // 打开电源灯 QThread::msleep(100);