修改菜单功能
This commit is contained in:
parent
ba3b79a076
commit
d1d8655645
273
Channel.cpp
273
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 <QCoreApplication>
|
||||
@ -8,40 +10,50 @@
|
||||
#include <QTime>
|
||||
#include <chrono>
|
||||
|
||||
LinkObject* Channel::audioInput = nullptr;
|
||||
LinkObject* Channel::audioOutput = nullptr;
|
||||
#include <QElapsedTimer>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
63
Channel.h
63
Channel.h
@ -1,6 +1,7 @@
|
||||
#ifndef CHANNEL_H
|
||||
#define CHANNEL_H
|
||||
|
||||
#include "Json.h"
|
||||
#include "Link.h"
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
@ -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
|
||||
|
@ -1,140 +0,0 @@
|
||||
#include "ChannelSetting.h"
|
||||
#include "Constant.h"
|
||||
#include "SerialPortTool.h"
|
||||
#include "ui_ChannelSetting.h"
|
||||
#include <Json.h>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
#include <QThread>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#ifndef CHANNELSETTING_H
|
||||
#define CHANNELSETTING_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
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
|
@ -1,269 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChannelSetting</class>
|
||||
<widget class="QWidget" name="ChannelSetting">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>391</width>
|
||||
<height>307</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
border: 5px solid red;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background: blue;
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QWidget {
|
||||
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);
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> 视频源设置</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777213</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>通道1</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_hdmi_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>HDMI</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_vga_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>VGA</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="2,3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777213</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>通道2</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_hdmi_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>HDMI</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_vga_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>VGA</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDone">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background: rgba(0,0,255,0.8);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>确定</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,5 +1,6 @@
|
||||
#include "CheckStorageThread.h"
|
||||
#include "Constant.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "Log.h"
|
||||
#include "Tool.h"
|
||||
#include <QFile>
|
||||
@ -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<DatabaseManager::File> 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();
|
||||
|
10
Constant.h
10
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
|
||||
|
279
DatabaseManager.cpp
Executable file
279
DatabaseManager.cpp
Executable file
@ -0,0 +1,279 @@
|
||||
#include "DatabaseManager.h"
|
||||
#include "Constant.h"
|
||||
#include "Log.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QMutex>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <QtSql/QSqlQuery>
|
||||
|
||||
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::File> DatabaseManager::get(QVariantMap params)
|
||||
{
|
||||
QList<DatabaseManager::File> 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<Channel>(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<DatabaseManager::Channel>(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::File> DatabaseManager::get(DatabaseManager::Channel chn)
|
||||
{
|
||||
QList<DatabaseManager::File> 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<DatabaseManager::Channel>(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::File> DatabaseManager::getTopTwo()
|
||||
{
|
||||
QList<DatabaseManager::File> 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<DatabaseManager::Channel>(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;
|
||||
}
|
||||
}
|
48
DatabaseManager.h
Executable file
48
DatabaseManager.h
Executable file
@ -0,0 +1,48 @@
|
||||
#ifndef DATABASEMANAGER_H
|
||||
#define DATABASEMANAGER_H
|
||||
#include <QSqlDatabase>
|
||||
#include <QVariantMap>
|
||||
|
||||
// 数据库管理类
|
||||
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<DatabaseManager::File> getTopTwo();
|
||||
|
||||
QList<DatabaseManager::File> get(QVariantMap params);
|
||||
QList<DatabaseManager::File> 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
|
320
FocusWindow.cpp
Executable file
320
FocusWindow.cpp
Executable file
@ -0,0 +1,320 @@
|
||||
#include <qapplication.h>
|
||||
#include "FocusWindow.h"
|
||||
|
||||
using namespace FW;
|
||||
|
||||
/**
|
||||
* @brief 判断某个控件是否为某个方向上的候选控件
|
||||
* @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 判断rect1与rect2在direction方向是否重叠
|
||||
* @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是否在source的direction方向上
|
||||
* @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 判断rect1相比与rect2相对于source在dircetion方向上是否更优
|
||||
* @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<QWidget*> 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();
|
||||
}
|
||||
}
|
||||
|
53
FocusWindow.h
Executable file
53
FocusWindow.h
Executable file
@ -0,0 +1,53 @@
|
||||
/*****************************************************************
|
||||
* @file FocusWindow.h
|
||||
* @brief 让qt窗体焦点能够上下左右移动的类,内部实现全部来自android源码焦点移动部分。
|
||||
* 在使用的时候需要继承这个类即可并重写getAllFocusabelWidget方法。
|
||||
* @author luoxiang
|
||||
* @date May 23 2024
|
||||
****************************************************************/
|
||||
#include <qwidget.h>
|
||||
#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<QWidget*> getAllFocusabelWidget() = 0;
|
||||
|
||||
private:
|
||||
QList<QWidget*> 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
|
||||
|
||||
|
1
Log.cpp
1
Log.cpp
@ -3,6 +3,7 @@
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
#include "spdlog/sinks/stdout_sinks.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <QDebug>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
|
404
Menu.cpp
404
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 <QDateTime>
|
||||
#include <QDesktopWidget>
|
||||
#include <QListView>
|
||||
#include <QTimer>
|
||||
|
||||
#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<QGridLayout*>(ui->scrollAreaWidgetContents->layout());
|
||||
|
||||
// 清除原来的控件防止内存泄漏
|
||||
QList<QWidget*> widgets = ui->scrollAreaWidgetContents->findChildren<QWidget*>();
|
||||
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<QPushButton*>(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<QPushButton*>(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<QComboBox*>(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<QComboBox*>(focusWidget->parent()->parent());
|
||||
if (cmb) {
|
||||
cmb->hidePopup();
|
||||
}
|
||||
}
|
||||
// 选择视频时按下确认
|
||||
else if (focusWidget->objectName().contains("btn_video")) {
|
||||
QPushButton* btn = qobject_cast<QPushButton*>(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<QPushButton*> btns = ui->scrollArea->findChildren<QPushButton*>();
|
||||
for (QPushButton* btn : btns) {
|
||||
if (btn->text() == str) {
|
||||
btn->setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 遍历当前窗体可以获取焦点的所有控件
|
||||
*/
|
||||
QList<QWidget*> Menu::getAllFocusabelWidget()
|
||||
{
|
||||
QList<QWidget*> list = findChildren<QWidget*>();
|
||||
QList<QWidget*> 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;
|
||||
}
|
||||
|
77
Menu.h
77
Menu.h
@ -1,23 +1,54 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
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 <QKeyEvent>
|
||||
|
||||
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<QWidget*> getAllFocusabelWidget() override;
|
||||
|
||||
private:
|
||||
Ui::Menu* ui;
|
||||
// 视频名数组列表
|
||||
QList<DatabaseManager::File> contentList;
|
||||
DatabaseManager* db;
|
||||
DatabaseManager::Channel currentChannel;
|
||||
QString currentFilename;
|
||||
|
||||
private:
|
||||
void getContents();
|
||||
void renderContents();
|
||||
void renderComboBoxYear();
|
||||
void renderComboBoxMonth();
|
||||
void renderComboBoxDay();
|
||||
};
|
||||
#endif // WIDGET_H
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef PROGRESSBAR_H
|
||||
#define PROGRESSBAR_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
@ -57,6 +60,9 @@
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
327
SerialPortTool.cpp.bak
Normal file
327
SerialPortTool.cpp.bak
Normal file
@ -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();
|
||||
}
|
@ -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 {
|
||||
|
88
SerialPortTool.h.bak
Normal file
88
SerialPortTool.h.bak
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef SERIALPORT_H
|
||||
#define SERIALPORT_H
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
#include <QTimer>
|
||||
|
||||
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<CommandType, QByteArray> cmdMap; // 指令列表
|
||||
QTimer* timer;
|
||||
};
|
||||
|
||||
#endif // SERIALPORT_H
|
@ -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 <QProcess>
|
||||
|
||||
extern const QList<Channel*> 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<DatabaseManager::File> 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("时间同步成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
Tool.cpp
16
Tool.cpp
@ -1,6 +1,7 @@
|
||||
#include "Tool.h"
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
|
||||
@ -121,3 +122,18 @@ int64_t Tool::getAvailableStorage(QString mountedPath)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取代码块运行的时间
|
||||
* @param callback
|
||||
* @return
|
||||
*/
|
||||
double Tool::getCostTime(std::function<void(void)> callback, const char* callbackName)
|
||||
{
|
||||
QElapsedTimer mstimer;
|
||||
mstimer.start();
|
||||
callback();
|
||||
double time = (double)mstimer.nsecsElapsed() / (double)1000000;
|
||||
qDebug() << callbackName << "cast time:" << time << "ms";
|
||||
return time;
|
||||
}
|
||||
|
5
Tool.h
5
Tool.h
@ -1,17 +1,22 @@
|
||||
#ifndef TOOL_H
|
||||
#define TOOL_H
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
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<void(void)> callback, const char* callbackName = "");
|
||||
};
|
||||
|
||||
#endif // TOOL_H
|
||||
|
671
Widget.cpp
671
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<LinkObject*>(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<Channel*>(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("未录制");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
33
Widget.h
33
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
|
||||
|
241
Widget.ui
241
Widget.ui
@ -19,7 +19,7 @@
|
||||
<string>Widget</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
<string notr="true">background: rgba(0,0,0,0); </string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
@ -51,48 +51,155 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblA">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="recordWidget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="res.qrc">:/images/record.png</pixmap>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: white;</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblImgB">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="res.qrc">:/images/record.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblTxtB">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: white;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>录制中</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblImgA">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="res.qrc">:/images/record.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblTxtA">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: white;</string>
|
||||
</property>
|
||||
<property name="midLineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>录制中</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblB">
|
||||
<property name="minimumSize">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="res.qrc">:/images/record.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@ -109,70 +216,22 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ProgressBar" name="progressBar" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1511</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>280</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>290</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QListWidget {
|
||||
color: rgba(255, 255, 255);
|
||||
outline: none;
|
||||
background-color: rgba(0, 0, 0, 0.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;
|
||||
}</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ProgressBar</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">ProgressBar.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="res.qrc"/>
|
||||
</resources>
|
||||
|
61
main.cpp
61
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 <QApplication>
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -16,6 +18,8 @@
|
||||
TcpServer* server;
|
||||
// 串口工具
|
||||
SerialPortTool* serialPortTool;
|
||||
// 数据库管理
|
||||
DatabaseManager* db;
|
||||
// 视频输出通道
|
||||
LinkObject* vo;
|
||||
LinkObject* vo1;
|
||||
@ -26,6 +30,8 @@ QList<Channel*> 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user