Compare commits
No commits in common. "dev" and "master" have entirely different histories.
305
Channel.cpp
305
Channel.cpp
@ -5,65 +5,46 @@
|
||||
#include "Log.h"
|
||||
#include "Tool.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QTime>
|
||||
#include <chrono>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
LinkObject* Channel::lineIn = nullptr;
|
||||
LinkObject* Channel::lineOut = nullptr;
|
||||
LinkObject* Channel::rtspServer = nullptr;
|
||||
LinkObject* Channel::resample = nullptr;
|
||||
LinkObject* Channel::gain = nullptr;
|
||||
LinkObject* Channel::volume = nullptr;
|
||||
// 这里设置最大12dB增益,最小30dB增益(超过12dB会爆音)
|
||||
int Channel::maxGian = 12;
|
||||
int Channel::minGain = -30;
|
||||
int Channel::curGain = 0;
|
||||
|
||||
extern LinkObject* vo;
|
||||
extern LinkObject* vo1;
|
||||
extern DatabaseManager* db;
|
||||
|
||||
void configureOutput2(QString resolutionStr);
|
||||
|
||||
Channel::Channel(const QString& name, const QVariantMap& params, QObject* parent)
|
||||
: channelName(name)
|
||||
, videoOutputParams(params)
|
||||
, QObject(parent)
|
||||
Channel::Channel(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
videoOutput = Link::create("OutputVo");
|
||||
videoOutput->start(videoOutputParams);
|
||||
videoInput = nullptr;
|
||||
videoOutput = nullptr;
|
||||
audioInput = nullptr;
|
||||
audioOutput = nullptr;
|
||||
videoEncoder = nullptr;
|
||||
audioEncoder = nullptr;
|
||||
record = nullptr;
|
||||
rtsp = nullptr;
|
||||
inputFile = nullptr;
|
||||
videoDecoder = nullptr;
|
||||
audioDecoder = nullptr;
|
||||
image = Link::create("InputImage");
|
||||
|
||||
resolutionMap[Channel::VO_OUTPUT_1080I60] = "1080I60";
|
||||
resolutionMap[Channel::VO_OUTPUT_1600x1200_60] = "1600x1200_60";
|
||||
resolutionMap[Channel::VO_OUTPUT_1280x1024_60] = "1280x1024_60";
|
||||
resolutionMap[Channel::VO_OUTPUT_1280x720_60] = "1280x720_60";
|
||||
resolutionMap[Channel::VO_OUTPUT_1024x768_60] = "1024x768_60";
|
||||
resolutionMap[Channel::VO_OUTPUT_800x600_60] = "800x600_60";
|
||||
}
|
||||
|
||||
Channel::~Channel()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化
|
||||
*/
|
||||
void Channel::init()
|
||||
{
|
||||
// 输出通道2的额外配置
|
||||
if (channelName == Constant::SecondaryChannel) {
|
||||
QString resolution = videoOutputParams["output"].toString();
|
||||
configureOutput2(resolution);
|
||||
}
|
||||
if (lineIn == nullptr) {
|
||||
lineIn = Link::create("InputAlsa");
|
||||
QVariantMap dataIn;
|
||||
dataIn["path"] = "hw:0";
|
||||
dataIn["path"] = "hw:0,0";
|
||||
dataIn["channels"] = 2;
|
||||
lineIn->start(dataIn);
|
||||
}
|
||||
if (resample == nullptr) {
|
||||
if (resample = nullptr) {
|
||||
resample = Link::create("Resample");
|
||||
resample->start();
|
||||
lineIn->linkA(resample);
|
||||
@ -71,26 +52,36 @@ void Channel::init()
|
||||
if (lineOut == nullptr) {
|
||||
lineOut = Link::create("OutputAlsa");
|
||||
QVariantMap dataOut;
|
||||
dataOut["path"] = "hw:0";
|
||||
dataOut["path"] = "hw:0,0";
|
||||
lineOut->start(dataOut);
|
||||
}
|
||||
if (gain == nullptr) {
|
||||
gain = Link::create("Gain");
|
||||
gain->start();
|
||||
}
|
||||
if (volume == nullptr) {
|
||||
volume = Link::create("Volume");
|
||||
volume->start();
|
||||
gain->linkA(volume);
|
||||
gain->linkA(lineOut);
|
||||
}
|
||||
if (rtspServer == nullptr) {
|
||||
rtspServer = Link::create("Rtsp");
|
||||
rtspServer->start();
|
||||
}
|
||||
image = Link::create("InputImage");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化
|
||||
*/
|
||||
void Channel::init()
|
||||
{
|
||||
if (channelName.isEmpty()) {
|
||||
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);
|
||||
@ -105,9 +96,6 @@ void Channel::init()
|
||||
videoInput->start(dataVi);
|
||||
videoInput->linkV(overlay)->linkV(videoOutput);
|
||||
|
||||
// 通道音频输出
|
||||
audioOutput = Link::create("OutputAo");
|
||||
|
||||
// 通道音频输入
|
||||
audioInput = Link::create("InputAi");
|
||||
QVariantMap dataAi;
|
||||
@ -116,6 +104,14 @@ void Channel::init()
|
||||
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);
|
||||
@ -134,7 +130,7 @@ void Channel::init()
|
||||
dataMp4["segmentDuration"] = duration;
|
||||
record->setData(dataMp4);
|
||||
videoInput->linkV(videoEncoder)->linkV(record);
|
||||
audioInput->linkA(audioEncoder)->linkV(record);
|
||||
audioInput->linkV(audioEncoder)->linkV(record);
|
||||
resample->linkA(audioEncoder)->linkA(record);
|
||||
|
||||
connect(record, SIGNAL(newEvent(QString, QVariant)), this, SLOT(onNewEvent(QString, QVariant)));
|
||||
@ -147,18 +143,6 @@ void Channel::init()
|
||||
// "onNewEvent");
|
||||
// });
|
||||
|
||||
// 用于计算文件时长
|
||||
calDuration = Link::create("InputFile");
|
||||
calDuration->start();
|
||||
|
||||
calAudioDecoder = Link::create("DecodeA");
|
||||
calAudioDecoder->start();
|
||||
calDuration->linkA(calAudioDecoder);
|
||||
|
||||
calVideoDecoder = Link::create("DecodeV");
|
||||
calVideoDecoder->start();
|
||||
calDuration->linkV(calVideoDecoder);
|
||||
|
||||
// rstp流
|
||||
rtsp = Link::create("Mux");
|
||||
QVariantMap dataRtsp;
|
||||
@ -182,7 +166,7 @@ void Channel::init()
|
||||
audioDecoder = Link::create("DecodeA");
|
||||
audioDecoder->start();
|
||||
if (channelName == Constant::MainChannel) {
|
||||
inputFile->linkA(audioDecoder)->linkA(gain);
|
||||
inputFile->linkA(audioDecoder)->linkA(lineOut);
|
||||
} else {
|
||||
inputFile->linkA(audioDecoder);
|
||||
}
|
||||
@ -193,62 +177,64 @@ void Channel::init()
|
||||
inputFile->linkV(videoDecoder)->linkV(videoOutput);
|
||||
}
|
||||
|
||||
void Channel::changeOutputResolution(Channel::Resolution resolution)
|
||||
{
|
||||
QVariantMap dataVo;
|
||||
dataVo["output"] = resolutionMap[resolution];
|
||||
videoOutput->setData(dataVo);
|
||||
if (channelName == Constant::SecondaryChannel) {
|
||||
configureOutput2(resolutionMap[resolution]);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::changeInputResolution(int width, int height)
|
||||
{
|
||||
QVariantMap dataVi;
|
||||
dataVi["width"] = width;
|
||||
dataVi["height"] = height;
|
||||
videoInput->setData(dataVi);
|
||||
|
||||
qDebug() << videoInput << "set "
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开始录制
|
||||
*/
|
||||
void Channel::startRecord()
|
||||
{
|
||||
QElapsedTimer mstimer;
|
||||
mstimer.start();
|
||||
// 记录本次录制开始时间以及当前视频录制的开始时间
|
||||
QString time = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
|
||||
startTime = time;
|
||||
curTime = time;
|
||||
QString curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
|
||||
startTime = curTime;
|
||||
currentTime = curTime;
|
||||
QVariantMap dataRecord;
|
||||
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());
|
||||
Log::info("open done {}", path.toStdString());
|
||||
|
||||
// 显示录制状态水印
|
||||
overlay->setData(recordOverlay);
|
||||
|
||||
float time = (double)mstimer.nsecsElapsed() / (double)1000000;
|
||||
qDebug() << channelName << "startRecord cast time:" << time << "ms";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 新事件槽函数,用于分段录制
|
||||
* @brief 新事件槽函数
|
||||
* @param msg 时间类型
|
||||
* @param data 数据
|
||||
*/
|
||||
void Channel::onNewEvent(QString msg, QVariant data)
|
||||
{
|
||||
if (msg == "newSegment") {
|
||||
QString datetime = curTime;
|
||||
// 重新设置视频的录制起始时间
|
||||
curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
|
||||
segmentId = data.toInt();
|
||||
// 异步执行保存文件信息的函数
|
||||
QTimer::singleShot(3000, this, [=]() {
|
||||
saveVideoInfo(datetime, segmentId - 1);
|
||||
});
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,14 +245,16 @@ void Channel::stopRecord()
|
||||
{
|
||||
Log::info("{} stop recording...", channelName.toStdString());
|
||||
record->stop(true);
|
||||
// 异步执行保存文件信息的函数
|
||||
QTimer::singleShot(1000, this, [=]() {
|
||||
saveVideoInfo(curTime, segmentId);
|
||||
});
|
||||
// 重置水印和时间
|
||||
// 将录制文件的信息存入数据库
|
||||
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);
|
||||
startTime = "";
|
||||
curTime = "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,7 +301,7 @@ bool Channel::startPlayback(QString path)
|
||||
videoDecoder->linkV(videoOutput);
|
||||
// 断开音频信号输出,启动回放输出
|
||||
audioInput->unLinkA(audioOutput);
|
||||
audioDecoder->linkA(gain);
|
||||
audioDecoder->linkA(lineOut);
|
||||
|
||||
playbackDuration = duration;
|
||||
state = Playback;
|
||||
@ -337,17 +325,30 @@ void Channel::startPlayLive()
|
||||
overlay->linkV(videoOutput);
|
||||
audioInput->linkA(audioOutput);
|
||||
// 关闭外部音频输出
|
||||
audioDecoder->unLinkA(gain);
|
||||
audioDecoder->unLinkA(lineOut);
|
||||
state = Stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 回放视频跳转
|
||||
* @param pos
|
||||
* @brief 后退10s
|
||||
*/
|
||||
void Channel::seek(int pos)
|
||||
void Channel::back()
|
||||
{
|
||||
inputFile->invoke("seek", pos);
|
||||
Log::info("{} back 10s", channelName.toStdString());
|
||||
int curPos = inputFile->invoke("getPosition").toInt();
|
||||
curPos -= 10 * 1000;
|
||||
inputFile->invoke("seek", curPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 快进10s
|
||||
*/
|
||||
void Channel::forward()
|
||||
{
|
||||
Log::info("{} forward 10s", channelName.toStdString());
|
||||
int curPos = inputFile->invoke("getPosition").toInt();
|
||||
curPos += 10 * 1000;
|
||||
inputFile->invoke("seek", curPos);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,7 +405,6 @@ void Channel::volumeUp()
|
||||
QVariantMap data;
|
||||
data["gain"] = curGain;
|
||||
gain->setData(data);
|
||||
Log::info("current volumn gain: {}dB", curGain);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -417,7 +417,6 @@ void Channel::volumeDown()
|
||||
QVariantMap data;
|
||||
data["gain"] = curGain;
|
||||
gain->setData(data);
|
||||
Log::info("current volumn gain: {}dB", curGain);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,79 +438,3 @@ void Channel::loadOverlayConfig()
|
||||
recordOverlay = loadFromJson(Constant::RecordOverlay);
|
||||
norecordOverlay = loadFromJson(Constant::NoRecordOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 修改文件名并获取视频时长,然后将信息保存到数据库中
|
||||
* @param startTime
|
||||
*/
|
||||
void Channel::saveVideoInfo(QString curTime, int segmentId)
|
||||
{
|
||||
// 修改文件名:本次录制起始时间_%d ==> 当前视频录制起始时间
|
||||
QString filename = QString("%1_%2.mp4").arg(startTime).arg(segmentId);
|
||||
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(channelName).arg(filename);
|
||||
QString newPath = QString("%1/%2/%3.mp4").arg(Constant::VideoPath).arg(channelName).arg(curTime);
|
||||
QFile file(path);
|
||||
if (!file.rename(newPath)) {
|
||||
Log::error("rename file name failed in function onNewEvent, old filename: {}, target filename: {} , channel name: {},reason: {}",
|
||||
path.toStdString(),
|
||||
newPath.toStdString(),
|
||||
channelName.toStdString(),
|
||||
file.errorString().toStdString());
|
||||
return;
|
||||
}
|
||||
// 获取视频文件的时间
|
||||
int curDuration = calDuration->invoke("getDuration", newPath).toInt() / 1000;
|
||||
// 将录制文件的信息存入数据库
|
||||
DatabaseManager::File fileInfo;
|
||||
fileInfo.channel = channelName == Constant::MainChannel
|
||||
? DatabaseManager::MainChannel
|
||||
: DatabaseManager::SecondaryChannel;
|
||||
fileInfo.datetime = QDateTime::fromString(curTime, "yyyyMMddhhmmss").toString("yyyy-MM-dd hh:mm:ss");
|
||||
fileInfo.filename = QString("%1.mp4").arg(curTime);
|
||||
fileInfo.duration = curDuration;
|
||||
if (db->insert(fileInfo)) {
|
||||
Log::info("insert one record into database success, name: {}, channel: {}, duration: {}s",
|
||||
fileInfo.filename.toStdString(),
|
||||
channelName.toStdString(),
|
||||
curDuration);
|
||||
} else {
|
||||
Log::error("insert one record into database failed, name: {}, channel: {}, duration: {}s",
|
||||
fileInfo.filename.toStdString(),
|
||||
channelName.toStdString(),
|
||||
curDuration);
|
||||
}
|
||||
// 更新当前录制录制视频的时间
|
||||
emit appendOneVideo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 针对输出口2的分辨率进行配置
|
||||
* @param resolutionStr
|
||||
*/
|
||||
void configureOutput2(QString resolutionStr)
|
||||
{
|
||||
static int lastNorm = 0;
|
||||
int norm = 0;
|
||||
int ddr = 0;
|
||||
if (resolutionStr == "1080P60")
|
||||
norm = 9;
|
||||
else if (resolutionStr == "1080P50")
|
||||
norm = 10;
|
||||
else if (resolutionStr == "1080P30")
|
||||
norm = 12;
|
||||
else if (resolutionStr == "720P60")
|
||||
norm = 5;
|
||||
else if (resolutionStr == "720P50")
|
||||
norm = 6;
|
||||
else if (resolutionStr == "3840x2160_30") {
|
||||
norm = 14;
|
||||
ddr = 1;
|
||||
}
|
||||
if (norm != lastNorm) {
|
||||
lastNorm = norm;
|
||||
QString cmd = "rmmod hi_lt8618sx_lp.ko";
|
||||
system(cmd.toLatin1().data());
|
||||
cmd = cmd.sprintf("insmod /ko/extdrv/hi_lt8618sx_lp.ko norm=%d USE_DDRCLK=%d", norm, ddr);
|
||||
system(cmd.toLatin1().data());
|
||||
}
|
||||
}
|
86
Channel.h
86
Channel.h
@ -16,107 +16,75 @@ public:
|
||||
Error,
|
||||
Finish
|
||||
};
|
||||
|
||||
enum Resolution {
|
||||
VO_OUTPUT_1080I60,
|
||||
VO_OUTPUT_1600x1200_60,
|
||||
VO_OUTPUT_1280x1024_60,
|
||||
VO_OUTPUT_1280x720_60,
|
||||
VO_OUTPUT_1024x768_60,
|
||||
VO_OUTPUT_800x600_60
|
||||
};
|
||||
|
||||
explicit Channel(const QString& name, const QVariantMap& params, QObject* parent = nullptr);
|
||||
~Channel();
|
||||
explicit Channel(QObject* parent = nullptr);
|
||||
void init();
|
||||
|
||||
// 输出分辨率
|
||||
void changeOutputResolution(Resolution resolution);
|
||||
void changeInputResolution(int width, int height);
|
||||
|
||||
// 录制
|
||||
void startRecord();
|
||||
void stopRecord();
|
||||
|
||||
// 回放
|
||||
bool startPlayback(QString path);
|
||||
void seek(int pos);
|
||||
void forward();
|
||||
void back();
|
||||
void togglePause();
|
||||
void startPlayLive();
|
||||
void showFinishPromot();
|
||||
|
||||
// 音量
|
||||
static QVariantMap getVolume();
|
||||
static void volumeUp();
|
||||
static void volumeDown();
|
||||
QVariantMap getVolume();
|
||||
void volumeUp();
|
||||
void volumeDown();
|
||||
|
||||
public:
|
||||
QString channelName;
|
||||
|
||||
// 视频输入输出
|
||||
LinkObject* videoInput = nullptr;
|
||||
LinkObject* videoOutput = nullptr;
|
||||
QVariantMap videoOutputParams;
|
||||
|
||||
// 视频编码
|
||||
LinkObject* videoEncoder = nullptr;
|
||||
LinkObject* videoInput;
|
||||
LinkObject* videoEncoder;
|
||||
QVariantMap videoEncoderParams;
|
||||
LinkObject* videoOutput;
|
||||
|
||||
// 外接音频输入输出
|
||||
static LinkObject* lineIn; // 外部音频输入
|
||||
static LinkObject* resample; // 重采样
|
||||
static LinkObject* lineOut; // 外部音频输出
|
||||
static LinkObject* gain; // 音量增益
|
||||
static LinkObject* volume; // 音量
|
||||
static int maxGian; // 最大增益
|
||||
static int minGain; // 最小增益
|
||||
static int curGain; // 当前增益
|
||||
LinkObject* gain; // 音量增益
|
||||
LinkObject* volume; // 音量
|
||||
int maxGian = 30;
|
||||
int minGain = -30;
|
||||
int curGain = 0;
|
||||
|
||||
// 通道音频输入输出
|
||||
LinkObject* audioInput = nullptr; // 通道音频输入
|
||||
LinkObject* audioOutput = nullptr; // 通道音频输入
|
||||
LinkObject* audioEncoder = nullptr; // 音频编码器
|
||||
LinkObject* audioInput; // 通道音频输入
|
||||
LinkObject* audioOutput; // 通道音频输入
|
||||
LinkObject* audioEncoder; // 音频编码器
|
||||
QVariantMap audioEncoderParams; // 编码参数
|
||||
|
||||
// 视频录制
|
||||
LinkObject* record = nullptr;
|
||||
LinkObject* calDuration = nullptr;
|
||||
LinkObject* calAudioDecoder = nullptr;
|
||||
LinkObject* calVideoDecoder = nullptr;
|
||||
int duration = 10 * 60 * 1000; // 单个视频时长
|
||||
LinkObject* record;
|
||||
int duration = 1 * 60 * 1000; // 单个视频时长
|
||||
bool isRecord = false;
|
||||
QString startTime; // 本次录制文件的开始时间
|
||||
QString curTime; // 当前录制文件的开始时间
|
||||
int segmentId = 0; // 分片录制的id
|
||||
|
||||
// 水印
|
||||
LinkObject* overlay = nullptr; // 水印,提示是否在录制视频
|
||||
QString currentTime; // 当前录制文件的开始时间
|
||||
int segmentId = 0;
|
||||
LinkObject* overlay; // 水印,提示是否在录制视频
|
||||
QVariantMap recordOverlay; // 录制状态下的水印参数
|
||||
QVariantMap norecordOverlay; // 非录制状态下的水印参数
|
||||
|
||||
// 视频回放
|
||||
int playbackDuration = 0; // 当前播放视频的时长,单位ms
|
||||
LinkObject* inputFile = nullptr;
|
||||
LinkObject* videoDecoder = nullptr;
|
||||
LinkObject* audioDecoder = nullptr;
|
||||
LinkObject* image = nullptr;
|
||||
LinkObject* inputFile;
|
||||
LinkObject* videoDecoder;
|
||||
LinkObject* audioDecoder;
|
||||
LinkObject* image;
|
||||
PlaybackState state = Stop;
|
||||
|
||||
// 视频推流
|
||||
static LinkObject* rtspServer;
|
||||
LinkObject* rtsp = nullptr;
|
||||
LinkObject* rtsp;
|
||||
QString pushCode;
|
||||
|
||||
QMap<Resolution, QString> resolutionMap; // 分辨率列表
|
||||
|
||||
private slots:
|
||||
void onNewEvent(QString msg, QVariant data);
|
||||
void saveVideoInfo(QString curTime, int segmentId);
|
||||
|
||||
signals:
|
||||
void playEnd();
|
||||
void showRecordState(bool state);
|
||||
void appendOneVideo();
|
||||
|
||||
private:
|
||||
void loadOverlayConfig();
|
||||
|
@ -17,8 +17,7 @@ extern QMutex mutex;
|
||||
extern QWaitCondition condition;
|
||||
extern DatabaseManager* db;
|
||||
|
||||
CheckStorageThread::CheckStorageThread(QObject* parent)
|
||||
: QThread(parent)
|
||||
CheckStorageThread::CheckStorageThread()
|
||||
{
|
||||
}
|
||||
|
||||
@ -35,7 +34,7 @@ void CheckStorageThread::run()
|
||||
// 从数据库中取出前两条数据,找到相关的文件删除
|
||||
QList<DatabaseManager::File> fileList = db->getTopTwo();
|
||||
for (auto& file : fileList) {
|
||||
QString filename = file.filename;
|
||||
QString filename = file.time;
|
||||
QString channel = file.channel == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
@ -56,7 +55,7 @@ void CheckStorageThread::run()
|
||||
Log::info("remove file {} success", path.toStdString());
|
||||
}
|
||||
// 从数据库清除这条记录
|
||||
db->remove(file.channel, file.filename);
|
||||
db->remove(file.channel, file.time);
|
||||
}
|
||||
} else {
|
||||
emit diskNotFull();
|
||||
|
@ -6,7 +6,7 @@
|
||||
class CheckStorageThread : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CheckStorageThread(QObject* parent = nullptr);
|
||||
CheckStorageThread();
|
||||
|
||||
signals:
|
||||
void diskWillFull(); // 磁盘空间不足
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
class Constant {
|
||||
public:
|
||||
Constant() { }
|
||||
Constant() {}
|
||||
enum RecordMode {
|
||||
NoChannelRecord,
|
||||
OneChannelRecord,
|
||||
@ -19,7 +19,6 @@ public:
|
||||
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* TimeSciptPath = "/opt/RecordControlApplication/scripts/rtc";
|
||||
static constexpr char* DatabasePath = "/opt/RecordControlApplication/database/data.db";
|
||||
static constexpr char* VideoPath = "/root/usb/videos";
|
||||
static constexpr char* MountedPath = "/root/usb";
|
||||
|
@ -66,16 +66,17 @@ void DatabaseManager::close()
|
||||
bool DatabaseManager::insert(File file)
|
||||
{
|
||||
QSqlQuery query;
|
||||
query.prepare("insert into file (channel, datetime, filename, duration) values (?, ?, ?, ?)");
|
||||
query.addBindValue(file.channel);
|
||||
query.addBindValue(file.datetime);
|
||||
query.addBindValue(file.filename);
|
||||
query.addBindValue(file.duration);
|
||||
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() + "," + query.lastError().driverText().toStdString());
|
||||
query.lastError().databaseText().toStdString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -89,33 +90,37 @@ QList<DatabaseManager::File> DatabaseManager::get(QVariantMap params)
|
||||
{
|
||||
QList<DatabaseManager::File> result;
|
||||
QSqlQuery query;
|
||||
QString sql = "select * from file where channel=? and datetime like ?";
|
||||
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;
|
||||
}
|
||||
query.prepare(sql);
|
||||
query.bindValue(0, chn);
|
||||
query.bindValue(1, QString("%1-%2-%3%").arg(year).arg(month).arg(day));
|
||||
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.datetime = query.value("datetime").toString();
|
||||
file.time = query.value("time").toString();
|
||||
file.filename = query.value("filename").toString();
|
||||
file.duration = query.value("duration").toInt();
|
||||
result.push_back(file);
|
||||
}
|
||||
} else {
|
||||
Log::error("select from database failed, reason: {}",
|
||||
query.lastError().databaseText().toStdString() + query.lastError().driverText().toStdString());
|
||||
query.lastError().databaseText().toStdString());
|
||||
}
|
||||
// Log::info("record of one day: {}", result.length());
|
||||
Log::info("record of one day: {}", result.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -135,10 +140,12 @@ QList<DatabaseManager::File> DatabaseManager::get(DatabaseManager::Channel chn)
|
||||
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.datetime = query.value("datetime").toString();
|
||||
file.time = query.value("time").toString();
|
||||
file.filename = query.value("filename").toString();
|
||||
file.duration = query.value("duration").toInt();
|
||||
result.push_back(file);
|
||||
}
|
||||
} else {
|
||||
@ -147,6 +154,7 @@ QList<DatabaseManager::File> DatabaseManager::get(DatabaseManager::Channel chn)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取前两条记录
|
||||
*/
|
||||
@ -159,10 +167,12 @@ QList<DatabaseManager::File> DatabaseManager::getTopTwo()
|
||||
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.datetime = query.value("datetime").toString();
|
||||
file.time = query.value("time").toString();
|
||||
file.filename = query.value("filename").toString();
|
||||
file.duration = query.value("duration").toInt();
|
||||
result.push_back(file);
|
||||
}
|
||||
} else {
|
||||
@ -180,11 +190,7 @@ QStringList DatabaseManager::getAllYears(Channel chn)
|
||||
{
|
||||
QStringList result;
|
||||
QSqlQuery query;
|
||||
query.prepare(R"(
|
||||
select distinct strftime('%Y', datetime) as year
|
||||
from file
|
||||
order by year
|
||||
)");
|
||||
query.prepare("select distinct year from file");
|
||||
if (query.exec()) {
|
||||
while (query.next()) {
|
||||
QString year = query.value(0).toString();
|
||||
@ -194,7 +200,7 @@ QStringList DatabaseManager::getAllYears(Channel chn)
|
||||
Log::error("select all years from database failed, reason: {}",
|
||||
query.lastError().databaseText().toStdString());
|
||||
}
|
||||
// Log::info("number of year: {}", result.length());
|
||||
Log::info("number of year: {}", result.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -207,14 +213,9 @@ QStringList DatabaseManager::getAllMonths(Channel chn, QString year)
|
||||
{
|
||||
QStringList result;
|
||||
QSqlQuery query;
|
||||
query.prepare(R"(
|
||||
select distinct strftime('%m', datetime) as month
|
||||
from file
|
||||
where channel = ? and strftime('%Y', datetime) = ?
|
||||
order by month
|
||||
)");
|
||||
query.addBindValue(chn);
|
||||
query.addBindValue(year);
|
||||
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();
|
||||
@ -222,9 +223,9 @@ QStringList DatabaseManager::getAllMonths(Channel chn, QString year)
|
||||
}
|
||||
} else {
|
||||
Log::error("select all months of one year from database failed, reason: {}",
|
||||
query.lastError().databaseText().toStdString() + query.lastError().driverText().toStdString());
|
||||
query.lastError().databaseText().toStdString());
|
||||
}
|
||||
// Log::info("number of month: {}", result.length());
|
||||
Log::info("number of month: {}", result.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -238,14 +239,7 @@ QStringList DatabaseManager::getAllDays(Channel chn, QString year, QString month
|
||||
{
|
||||
QStringList result;
|
||||
QSqlQuery query;
|
||||
query.prepare(R"(
|
||||
select distinct strftime('%d', datetime) as day
|
||||
from file
|
||||
where channel = ?
|
||||
and strftime('%Y', datetime) = ?
|
||||
and strftime('%m', datetime) = ?
|
||||
order by day
|
||||
)");
|
||||
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);
|
||||
@ -256,62 +250,30 @@ QStringList DatabaseManager::getAllDays(Channel chn, QString year, QString month
|
||||
}
|
||||
} else {
|
||||
Log::error("select all days of one month from database failed, reason: {}",
|
||||
query.lastError().databaseText().toStdString() + query.lastError().driverText().toStdString());
|
||||
query.lastError().databaseText().toStdString());
|
||||
}
|
||||
// Log::info("number of day: {}", result.length());
|
||||
Log::info("number of day: {}", result.length());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据通道和文件名删除记录,文件名格式yyyyMMddhhmmss
|
||||
* @brief 根据通道和文件名删除记录
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool DatabaseManager::remove(DatabaseManager::Channel chn, QString name)
|
||||
{
|
||||
int id = -1;
|
||||
// 找到对应记录
|
||||
QSqlQuery query;
|
||||
query.prepare("select * from file where channel = ? and filename = ?");
|
||||
query.prepare("delet from file where channel = ? and name = ?");
|
||||
query.bindValue(0, chn);
|
||||
query.bindValue(1, name);
|
||||
if (query.exec()) {
|
||||
while (query.next()) {
|
||||
id = query.value(0).toInt();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Log::info("cannot find the record, channel = {}, name = {}",
|
||||
int(chn),
|
||||
name.toStdString());
|
||||
return false;
|
||||
}
|
||||
// 未找到
|
||||
if (id == -1) {
|
||||
Log::info("cannot find the record, channel = {}, name = {}",
|
||||
int(chn),
|
||||
name.toStdString());
|
||||
return false;
|
||||
}
|
||||
Log::info("find the record, channel = {} , name = {}, and the id = {}",
|
||||
int(chn),
|
||||
name.toStdString(),
|
||||
id);
|
||||
query.clear();
|
||||
// 删除文件
|
||||
query.prepare("delete from file where id = ?");
|
||||
query.bindValue(0, id);
|
||||
if (query.exec()) {
|
||||
Log::info("delete one record from database, id = {}, channel = {}, name = {}",
|
||||
id,
|
||||
int(chn),
|
||||
name.toStdString());
|
||||
return true;
|
||||
} else {
|
||||
Log::error("delete one record from database failed, channel = {}, name = {}, reason: {}",
|
||||
(int)chn,
|
||||
name.toStdString(),
|
||||
query.lastError().driverText().toStdString() + ", " + query.lastError().databaseText().toStdString());
|
||||
query.lastError().databaseText().toStdString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,11 @@ public:
|
||||
struct File {
|
||||
int id; // id
|
||||
Channel channel; // 通道
|
||||
QString datetime; // 时间 yyyy-MM-dd hh:mm:ss
|
||||
QString filename; // 文件名
|
||||
int duration; // 时间
|
||||
QString year; // 年
|
||||
QString month; // 月
|
||||
QString day; // 日
|
||||
QString time; // 时分秒,hh:mm:ss
|
||||
QString filename; // 真实路径
|
||||
};
|
||||
static DatabaseManager* getInstace();
|
||||
~DatabaseManager();
|
||||
@ -28,6 +30,7 @@ public:
|
||||
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);
|
||||
|
417
Menu.cpp
417
Menu.cpp
@ -1,17 +1,16 @@
|
||||
#include "Menu.h"
|
||||
#include "Channel.h"
|
||||
#include "Constant.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "Log.h"
|
||||
#include "Tool.h"
|
||||
#include "ui_Menu.h"
|
||||
#include <QDateTime>
|
||||
#include <QDesktopWidget>
|
||||
#include <QListView>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
|
||||
extern QList<Channel*> channelList;
|
||||
#define CONTENT_ROW 6 // 列表行
|
||||
#define CONTENT_COLUMN 6 // 列表列
|
||||
#define CONTENT_CELL_HEIGHT 56 // 单元格高度
|
||||
|
||||
Menu::Menu(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
@ -26,41 +25,48 @@ Menu::Menu(QWidget* parent)
|
||||
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());
|
||||
ui->cmbResolutionA->setView(new QListView());
|
||||
ui->cmbResolutionB->setView(new QListView());
|
||||
ui->cmbResolutionInA->setView(new QListView());
|
||||
ui->cmbResolutionInB->setView(new QListView());
|
||||
ui->timeSlider->setOpacity(0.5);
|
||||
|
||||
// 默认设置当前操作选择主通道
|
||||
curSelectChannel = DatabaseManager::MainChannel;
|
||||
// 设置ScrollArea为栅格布局
|
||||
QGridLayout* layout = new QGridLayout(ui->scrollArea);
|
||||
ui->scrollAreaWidgetContents->setLayout(layout);
|
||||
|
||||
db = DatabaseManager::getInstace();
|
||||
if (!db->open())
|
||||
return;
|
||||
|
||||
// 设置ScrollArea为栅格布局
|
||||
connect(ui->cmbYear, &QComboBox::currentTextChanged, [=](QString text) {
|
||||
renderComboBoxMonth();
|
||||
});
|
||||
connect(ui->cmbMonth, &QComboBox::currentTextChanged, [=](QString text) {
|
||||
renderComboBoxDay();
|
||||
});
|
||||
|
||||
for (const auto& chn : channelList) {
|
||||
connect(chn, SIGNAL(appendOneVideo()), this, SLOT(onAppendVideo()));
|
||||
}
|
||||
|
||||
renderComboBoxYear();
|
||||
renderTimeSlider();
|
||||
// 默认设置当前操作选择主通道
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +75,6 @@ Menu::~Menu()
|
||||
*/
|
||||
void Menu::setChannelSelectVisible(bool visible)
|
||||
{
|
||||
channelSelectVisible = visible;
|
||||
ui->widget_chnSelect->setVisible(visible);
|
||||
}
|
||||
|
||||
@ -78,7 +83,7 @@ void Menu::setChannelSelectVisible(bool visible)
|
||||
*/
|
||||
void Menu::renderComboBoxYear()
|
||||
{
|
||||
QStringList years = db->getAllYears(curSelectChannel);
|
||||
QStringList years = db->getAllYears(currentChannel);
|
||||
|
||||
ui->cmbYear->clear();
|
||||
for (auto& str : years) {
|
||||
@ -96,7 +101,7 @@ void Menu::renderComboBoxMonth()
|
||||
if (year.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QStringList months = db->getAllMonths(curSelectChannel, year);
|
||||
QStringList months = db->getAllMonths(currentChannel, year);
|
||||
ui->cmbMonth->clear();
|
||||
for (auto& str : months) {
|
||||
ui->cmbMonth->addItem(str);
|
||||
@ -114,7 +119,7 @@ void Menu::renderComboBoxDay()
|
||||
if (year.isEmpty() || year.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QStringList days = db->getAllDays(curSelectChannel, year, month);
|
||||
QStringList days = db->getAllDays(currentChannel, year, month);
|
||||
ui->cmbDay->clear();
|
||||
for (auto& str : days) {
|
||||
ui->cmbDay->addItem(str);
|
||||
@ -122,6 +127,66 @@ void Menu::renderComboBoxDay()
|
||||
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
|
||||
@ -129,51 +194,30 @@ void Menu::renderComboBoxDay()
|
||||
void Menu::move(Direction direction)
|
||||
{
|
||||
QWidget* focusWidget = QApplication::focusWidget();
|
||||
if (!focusWidget) {
|
||||
return;
|
||||
}
|
||||
// 当前焦点是否在展开后的ComboBox上
|
||||
bool isCmbPopup = (strcmp(focusWidget->metaObject()->className(), "QListView") == 0);
|
||||
bool isTimeSlider = focusWidget->objectName() == "timeSlider";
|
||||
// 下拉框展开,则只进行上下选择
|
||||
if (isCmbPopup) {
|
||||
// 随便赋值一个不影响功能的按键
|
||||
Qt::Key key = Qt::Key_Right;
|
||||
if (direction == Up) {
|
||||
key = Qt::Key_Up;
|
||||
key == Qt::Key_Up;
|
||||
} else if (direction == Down) {
|
||||
key = Qt::Key_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 if (isTimeSlider) {
|
||||
switch (direction) {
|
||||
case Left:
|
||||
if (curSegmentIndex > 0) {
|
||||
curSegmentIndex--;
|
||||
int cur = segments[curSegmentIndex].startTime;
|
||||
ui->timeSlider->setCurrent(cur);
|
||||
}
|
||||
break;
|
||||
case Right:
|
||||
if (curSegmentIndex < segments.length() - 1) {
|
||||
curSegmentIndex++;
|
||||
int cur = segments[curSegmentIndex].startTime;
|
||||
ui->timeSlider->setCurrent(cur);
|
||||
}
|
||||
break;
|
||||
case Up:
|
||||
case Down:
|
||||
focusNext(direction);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} 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);
|
||||
@ -189,64 +233,118 @@ void Menu::move(Direction direction)
|
||||
*/
|
||||
void Menu::confirm()
|
||||
{
|
||||
int index = ui->stackedWidget->currentIndex();
|
||||
QWidget* focusWidget = QApplication::focusWidget();
|
||||
// 当前操作的是按钮
|
||||
if (strcmp(focusWidget->metaObject()->className(), "QPushButton") == 0) {
|
||||
switch (index) {
|
||||
// 通道设置界面
|
||||
case 0: {
|
||||
QPushButton* btn = qobject_cast<QPushButton*>(focusWidget);
|
||||
if (btn) {
|
||||
// 选择通道输出类型
|
||||
if (btn == ui->btn_hdmi_1) {
|
||||
btn->setChecked(true);
|
||||
emit btnHdmi1Checked();
|
||||
} else if (btn == ui->btn_hdmi_2) {
|
||||
btn->setChecked(true);
|
||||
emit btnHdmi2Checked();
|
||||
} else if (btn == ui->btn_vga_1) {
|
||||
btn->setChecked(true);
|
||||
emit btnVga1Checked();
|
||||
} else if (btn == ui->btn_vga_2) {
|
||||
btn->setChecked(true);
|
||||
emit btnVga2Checked();
|
||||
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);
|
||||
}
|
||||
// 选择通道
|
||||
else if (btn == ui->btn_channel_1 || btn == ui->btn_channel_2) {
|
||||
btn->setChecked(true);
|
||||
curSelectChannel = btn == ui->btn_channel_1 ? DatabaseManager::MainChannel
|
||||
: DatabaseManager::SecondaryChannel;
|
||||
renderComboBoxYear();
|
||||
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;
|
||||
}
|
||||
// 当前操作下拉框
|
||||
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)
|
||||
QListView* listView = static_cast<QListView*>(focusWidget);
|
||||
QComboBox* cmb = static_cast<QComboBox*>(listView->parent()->parent());
|
||||
if (cmb) {
|
||||
cmb->setCurrentIndex(listView->currentIndex().row());
|
||||
cmb->hidePopup();
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 选中进度条
|
||||
else if (focusWidget->objectName() == "timeSlider") {
|
||||
QVariantMap params;
|
||||
params["channel"] = curSelectChannel;
|
||||
params["year"] = ui->cmbYear->currentText();
|
||||
params["month"] = ui->cmbMonth->currentText();
|
||||
params["day"] = ui->cmbDay->currentText();
|
||||
emit btnPlaybackClicked(params, curSegmentIndex);
|
||||
hide();
|
||||
QString filename;
|
||||
// 上一个视频
|
||||
if (type == "previous") {
|
||||
if (index == 0) {
|
||||
emit btnVideoClicked("first");
|
||||
return;
|
||||
}
|
||||
filename = contentList[index - 1].filename;
|
||||
}
|
||||
// 确认按钮按下确认
|
||||
else if (focusWidget->objectName() == "btn_done") {
|
||||
renderTimeSlider();
|
||||
// 下一个视频
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,120 +365,3 @@ QList<QWidget*> Menu::getAllFocusabelWidget()
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前正在回放的通道
|
||||
* @return
|
||||
*/
|
||||
DatabaseManager::Channel Menu::getCurPlayChannel()
|
||||
{
|
||||
return curSelectChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染回放时间轴
|
||||
*/
|
||||
void Menu::renderTimeSlider()
|
||||
{
|
||||
QVariantMap params;
|
||||
params["channel"] = curSelectChannel;
|
||||
params["year"] = ui->cmbYear->currentText();
|
||||
params["month"] = ui->cmbMonth->currentText();
|
||||
params["day"] = ui->cmbDay->currentText();
|
||||
QList<TimeSlider::TimeSegment> segs = Tool::calTimeSegments(params);
|
||||
if (segs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ui->timeSlider->setTimeSegments(segs);
|
||||
ui->timeSlider->setCurrent(segs.front().startTime);
|
||||
segments = segs;
|
||||
curSegmentIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 新录制完一个视频槽函数
|
||||
*/
|
||||
void Menu::onAppendVideo()
|
||||
{
|
||||
Channel* chn = static_cast<Channel*>(sender());
|
||||
// 一路回放
|
||||
if (ui->widget_chnSelect->isVisible()) {
|
||||
DatabaseManager::Channel c = static_cast<DatabaseManager::Channel>(curSelectChannel);
|
||||
QString channelName = c == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
if (chn->channelName != channelName) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 两路回放
|
||||
else {
|
||||
if (chn->channelName != Constant::MainChannel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 刷新时间轴中时间片的显示
|
||||
QVariantMap params;
|
||||
params["channel"] = curSelectChannel;
|
||||
params["year"] = ui->cmbYear->currentText();
|
||||
params["month"] = ui->cmbMonth->currentText();
|
||||
params["day"] = ui->cmbDay->currentText();
|
||||
segments = Tool::calTimeSegments(params);
|
||||
ui->timeSlider->setTimeSegments(segments);
|
||||
}
|
||||
|
||||
void Menu::on_cmbResolutionB_currentIndexChanged(int index)
|
||||
{
|
||||
emit resolutionOutBChanged(index);
|
||||
}
|
||||
|
||||
void Menu::on_cmbResolutionA_currentIndexChanged(int index)
|
||||
{
|
||||
emit resolutionOutAChanged(index);
|
||||
}
|
||||
|
||||
void Menu::moveToCenter()
|
||||
{
|
||||
QWidget* p = static_cast<QWidget*>(parent());
|
||||
if (p) {
|
||||
// 获取父窗体的位置和尺寸
|
||||
QRect parentGeometry = p->geometry();
|
||||
|
||||
// 计算子窗体的居中位置
|
||||
int x = parentGeometry.left() + (parentGeometry.width() - width()) / 2;
|
||||
int y = parentGeometry.top() + (parentGeometry.height() - height()) / 2;
|
||||
// 移动子窗体到父窗体的中心
|
||||
QWidget::move(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::show()
|
||||
{
|
||||
QWidget::show();
|
||||
moveToCenter();
|
||||
ui->btnChannelSetting->setFocus();
|
||||
}
|
||||
|
||||
Menu* Menu::restartUI()
|
||||
{
|
||||
Menu* menu = new Menu();
|
||||
close();
|
||||
menu->show();
|
||||
return menu;
|
||||
}
|
||||
|
||||
void Menu::on_cmbResolutionInA_currentIndexChanged(const QString& text)
|
||||
{
|
||||
QStringList list = text.split("x");
|
||||
if (list.count() == 2) {
|
||||
emit resolutionInAChanged(list[0].toInt(), list[1].toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::on_cmbResolutionInB_currentIndexChanged(const QString& text)
|
||||
{
|
||||
QStringList list = text.split("x");
|
||||
if (list.count() == 2) {
|
||||
emit resolutionInAChanged(list[0].toInt(), list[1].toInt());
|
||||
}
|
||||
}
|
||||
|
39
Menu.h
39
Menu.h
@ -1,12 +1,9 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
|
||||
#include "Channel.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "FocusWindow.h"
|
||||
#include "TimeSlider.h"
|
||||
#include <QKeyEvent>
|
||||
#include <QMap>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
@ -19,55 +16,39 @@ class Menu : public QWidget, public FW::FocusWindow {
|
||||
public:
|
||||
Menu(QWidget* parent = nullptr);
|
||||
~Menu();
|
||||
void setChannelSelectVisible(bool visible);
|
||||
DatabaseManager::Channel getCurPlayChannel();
|
||||
void moveToCenter();
|
||||
void show();
|
||||
Menu* restartUI();
|
||||
void setChannelSelectVisible(bool visible);
|
||||
|
||||
public slots:
|
||||
void move(Direction direction);
|
||||
void confirm();
|
||||
void onAppendVideo();
|
||||
void clickVideo(QString type);
|
||||
|
||||
signals:
|
||||
void btnHdmi1Checked();
|
||||
void btnHdmi2Checked();
|
||||
void btnVga1Checked();
|
||||
void btnVga2Checked();
|
||||
void btnPlaybackClicked(QVariantMap params, int segmentIndex);
|
||||
|
||||
void resolutionOutAChanged(int);
|
||||
void resolutionOutBChanged(int);
|
||||
|
||||
void resolutionInAChanged(int width, int height);
|
||||
void resolutionInBChanged(int width, int height);
|
||||
void btnVideoClicked(QString name);
|
||||
void curChannelChanged(QString channel);
|
||||
|
||||
protected:
|
||||
// 重写父类的方法,以获取当前界面的所有可以获取焦点的控件
|
||||
QList<QWidget*> getAllFocusabelWidget() override;
|
||||
|
||||
private slots:
|
||||
void on_cmbResolutionB_currentIndexChanged(int index);
|
||||
|
||||
void on_cmbResolutionA_currentIndexChanged(int index);
|
||||
|
||||
void on_cmbResolutionInA_currentIndexChanged(const QString& arg1);
|
||||
|
||||
void on_cmbResolutionInB_currentIndexChanged(const QString& arg1);
|
||||
|
||||
private:
|
||||
Ui::Menu* ui;
|
||||
// 视频名数组列表
|
||||
QList<DatabaseManager::File> contentList;
|
||||
DatabaseManager* db;
|
||||
bool channelSelectVisible = false; // 是否显示通道选择,单通道回放显示、双通道不显示
|
||||
DatabaseManager::Channel curSelectChannel; // 当前选择的通道
|
||||
QList<TimeSlider::TimeSegment> segments; // 视频时间片
|
||||
int curSegmentIndex; // 当前时间片
|
||||
DatabaseManager::Channel currentChannel;
|
||||
QString currentFilename;
|
||||
|
||||
private:
|
||||
void getContents();
|
||||
void renderContents();
|
||||
void renderComboBoxYear();
|
||||
void renderComboBoxMonth();
|
||||
void renderComboBoxDay();
|
||||
void renderTimeSlider();
|
||||
};
|
||||
#endif // WIDGET_H
|
||||
|
123
Message.cpp
Executable file
123
Message.cpp
Executable file
@ -0,0 +1,123 @@
|
||||
#include "Message.h"
|
||||
#include <QSpacerItem>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
Message::Message(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
btnStyle = "QPushButton { \
|
||||
background: rgba(0,0,0,0.4); \
|
||||
color: rgba(255,255,255); \
|
||||
border: none; \
|
||||
border-radius: 10px; \
|
||||
min-height: 40px; \
|
||||
}";
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(QMargins(10, 10, 10, 10));
|
||||
layout->setSpacing(10);
|
||||
this->setLayout(layout);
|
||||
this->setFixedHeight(260);
|
||||
QFont font;
|
||||
// font.setFamily("Ubuntu Regular");
|
||||
font.setPixelSize(16);
|
||||
this->setFont(font);
|
||||
|
||||
QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
layout->addSpacerItem(verticalSpacer);
|
||||
}
|
||||
|
||||
Message::~Message()
|
||||
{
|
||||
}
|
||||
|
||||
void Message::success(QString content, int duration)
|
||||
{
|
||||
showMessage(content, duration, Success);
|
||||
}
|
||||
|
||||
void Message::info(QString content, int duration)
|
||||
{
|
||||
showMessage(content, duration, Info);
|
||||
}
|
||||
|
||||
void Message::error(QString content, int duration)
|
||||
{
|
||||
showMessage(content, duration, Error);
|
||||
}
|
||||
|
||||
void Message::warning(QString content, int duration)
|
||||
{
|
||||
showMessage(content, duration, Warning);
|
||||
}
|
||||
|
||||
void Message::showMessage(QString content, int duration, Level level)
|
||||
{
|
||||
QVBoxLayout* layout = static_cast<QVBoxLayout*>(this->layout());
|
||||
if (count >= maxCount) {
|
||||
// remove first
|
||||
QPair<QPushButton*, QTimer*> pair = contentList.first();
|
||||
contentList.removeFirst();
|
||||
layout->removeWidget(pair.first);
|
||||
delete pair.first;
|
||||
delete pair.second;
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
// apeend new
|
||||
QPushButton* btn = generateButton(content, level);
|
||||
layout->insertWidget(count, btn);
|
||||
|
||||
QTimer* timer = new QTimer();
|
||||
timer->setInterval(duration);
|
||||
timer->start();
|
||||
QPair<QPushButton*, QTimer*> pair(btn, timer);
|
||||
contentList.append(pair);
|
||||
count += 1;
|
||||
|
||||
connect(timer, &QTimer::timeout, [=] {
|
||||
for (int i = 0; i < contentList.length(); i++) {
|
||||
QPair<QPushButton*, QTimer*> pair = contentList.at(i);
|
||||
if (pair.first == btn) {
|
||||
contentList.removeAt(i);
|
||||
}
|
||||
layout->removeWidget(pair.first);
|
||||
delete pair.first;
|
||||
delete pair.second;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QPushButton* Message::generateButton(QString content, Level level)
|
||||
{
|
||||
QPushButton* btn = new QPushButton(this);
|
||||
btn->setText(content);
|
||||
QString iconPath;
|
||||
switch (level) {
|
||||
case Info:
|
||||
iconPath = ":/icons/info.png";
|
||||
break;
|
||||
case Success:
|
||||
iconPath = ":/icons/success.png";
|
||||
break;
|
||||
case Error:
|
||||
iconPath = ":/icons/error.png";
|
||||
case Warning:
|
||||
iconPath = ":/icons/waring.png";
|
||||
break;
|
||||
default:
|
||||
iconPath = ":/icons/info.png";
|
||||
break;
|
||||
}
|
||||
btn->setIcon(QIcon(iconPath));
|
||||
btn->setIconSize(QSize(16, 16));
|
||||
btn->setStyleSheet(btnStyle);
|
||||
|
||||
QFont font = btn->font();
|
||||
QFontMetrics metrics(font);
|
||||
int width = metrics.boundingRect(content).size().width();
|
||||
btn->setFixedWidth(width);
|
||||
|
||||
return btn;
|
||||
}
|
43
Message.h
Executable file
43
Message.h
Executable file
@ -0,0 +1,43 @@
|
||||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPair>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
class Message : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Level {
|
||||
Success,
|
||||
Error,
|
||||
Info,
|
||||
Warning
|
||||
};
|
||||
explicit Message(QWidget* parent = 0);
|
||||
~Message();
|
||||
|
||||
void success(QString content, int duration);
|
||||
void error(QString content, int duration);
|
||||
void info(QString content, int duration);
|
||||
void warning(QString content, int duration);
|
||||
|
||||
private:
|
||||
Level level = Info;
|
||||
bool isShow = false;
|
||||
|
||||
int count = 0;
|
||||
int maxCount = 5;
|
||||
QList<QPair<QPushButton*, QTimer*>> contentList;
|
||||
|
||||
QString btnStyle;
|
||||
|
||||
private:
|
||||
void showMessage(QString content, int duration, Level level);
|
||||
QPushButton* generateButton(QString content, Level level);
|
||||
};
|
||||
|
||||
#endif // MESSAGE_H
|
120
ProgressBar.cpp
Executable file
120
ProgressBar.cpp
Executable file
@ -0,0 +1,120 @@
|
||||
#include "ProgressBar.h"
|
||||
#include "ui_ProgressBar.h"
|
||||
#include <QDebug>
|
||||
|
||||
#define DURATION 10000
|
||||
|
||||
ProgressBar::ProgressBar(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::ProgressBar)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// move to bottom of screen
|
||||
this->setFixedWidth(parent->width());
|
||||
int height = parent->height();
|
||||
this->move(0, height - this->height());
|
||||
|
||||
timer = new QTimer();
|
||||
timer->setInterval(DURATION);
|
||||
timer->stop();
|
||||
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
|
||||
|
||||
QString styles = "QSlider::groove:horizontal { \
|
||||
border: none; \
|
||||
height: 6px; \
|
||||
border-radius: 3px; \
|
||||
background: #FF5C38; \
|
||||
} \
|
||||
QSlider::sub-page:horizontal { \
|
||||
background: #FF5C38; \
|
||||
height: 4px; \
|
||||
border-radius: 3px; \
|
||||
} \
|
||||
QSlider::add-page:horizontal { \
|
||||
background: #949494; \
|
||||
height: 4px; \
|
||||
border-radius: 3px; \
|
||||
}";
|
||||
QString max = "QSlider::handle:horizontal {\
|
||||
border: none;\
|
||||
margin: -5px 0px;\
|
||||
width: 16px;\
|
||||
height: 16px;\
|
||||
border-radius: 8px;\
|
||||
background: #FF5C38;\
|
||||
}";
|
||||
QString min = "QSlider::handle:horizontal {\
|
||||
border: none;\
|
||||
margin: -5px -8px;\
|
||||
width: 16px;\
|
||||
height: 16px;\
|
||||
border-radius: 8px;\
|
||||
background: rgba(0, 0, 0, 0);\
|
||||
}";
|
||||
sliderMaxStyles = styles + max;
|
||||
sliderMinStyles = styles + min;
|
||||
|
||||
this->setStyleSheet(sliderMaxStyles);
|
||||
}
|
||||
|
||||
ProgressBar::~ProgressBar()
|
||||
{
|
||||
delete ui;
|
||||
delete timer;
|
||||
}
|
||||
|
||||
void ProgressBar::setDuration(int dur)
|
||||
{
|
||||
this->duration = dur;
|
||||
ui->horizontalSlider->setMaximum(dur);
|
||||
QString time = this->msecToString(dur);
|
||||
this->durationStr = time;
|
||||
ui->label->setText(QString("00:00:00/%1").arg(time));
|
||||
}
|
||||
|
||||
void ProgressBar::setCurrent(int cur)
|
||||
{
|
||||
ui->horizontalSlider->setValue(cur);
|
||||
QString time = this->msecToString(cur);
|
||||
ui->label->setText(QString("%1/%2").arg(time).arg(durationStr));
|
||||
}
|
||||
|
||||
void ProgressBar::showMax()
|
||||
{
|
||||
if (timer->isActive()) {
|
||||
timer->stop();
|
||||
timer->start();
|
||||
} else {
|
||||
timer->start();
|
||||
}
|
||||
if (!isMax) {
|
||||
this->setFixedHeight(100);
|
||||
ui->horizontalSlider->setStyleSheet(sliderMaxStyles);
|
||||
this->move(0, parentWidget()->height() - this->height());
|
||||
ui->widget->setStyleSheet("QWidget#widget{background-color: rgba(0, 0, 0, 0.7);}");
|
||||
isMax = true;
|
||||
ui->actionContainer->show();
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressBar::onTimeout()
|
||||
{
|
||||
ui->actionContainer->hide();
|
||||
ui->horizontalSlider->setStyleSheet(sliderMinStyles);
|
||||
this->setFixedHeight(ui->horizontalSlider->height() + ui->widget->layout()->contentsMargins().top());
|
||||
this->move(0, parentWidget()->height() - this->height());
|
||||
ui->widget->setStyleSheet("QWidget#widget{background-color: rgba(0, 0, 0, 0);}");
|
||||
timer->stop();
|
||||
isMax = false;
|
||||
}
|
||||
|
||||
void ProgressBar::setState(PlayState state)
|
||||
{
|
||||
if (state == Play) {
|
||||
ui->lblStatus->setPixmap(QPixmap(":/images/pause.png"));
|
||||
} else {
|
||||
ui->lblStatus->setPixmap(QPixmap(":/images/start.png"));
|
||||
}
|
||||
}
|
51
ProgressBar.h
Executable file
51
ProgressBar.h
Executable file
@ -0,0 +1,51 @@
|
||||
#ifndef PROGRESSBAR_H
|
||||
#define PROGRESSBAR_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ProgressBar;
|
||||
}
|
||||
|
||||
class ProgressBar : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum PlayState {
|
||||
Play,
|
||||
Pause
|
||||
};
|
||||
explicit ProgressBar(QWidget* parent = 0);
|
||||
~ProgressBar();
|
||||
void showMax();
|
||||
void setDuration(int dur);
|
||||
void setCurrent(int cur);
|
||||
void setState(PlayState state);
|
||||
inline QString msecToString(int msc);
|
||||
|
||||
private slots:
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
Ui::ProgressBar* ui;
|
||||
int duration;
|
||||
QString durationStr;
|
||||
|
||||
QTimer* timer;
|
||||
bool isMax = true;
|
||||
|
||||
QString sliderMaxStyles;
|
||||
QString sliderMinStyles;
|
||||
};
|
||||
|
||||
inline QString ProgressBar::msecToString(int msc)
|
||||
{
|
||||
QString formatStr = QTime(0, 0, 0).addMSecs(msc).toString(QString::fromUtf8("hh:mm:ss"));
|
||||
qDebug() << msc;
|
||||
return formatStr;
|
||||
}
|
||||
|
||||
#endif // PROGRESSBAR_H
|
144
ProgressBar.ui
Executable file
144
ProgressBar.ui
Executable file
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProgressBar</class>
|
||||
<widget class="QWidget" name="ProgressBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>776</width>
|
||||
<height>100</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QWidget#widget {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="actionContainer" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblStatus">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap>:/images/begin.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLabel {
|
||||
color: #ffffff;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00:00:00/00:00:00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -34,6 +34,8 @@ SOURCES += \
|
||||
TcpServer.cpp \
|
||||
Channel.cpp \
|
||||
Menu.cpp\
|
||||
ProgressBar.cpp \
|
||||
Message.cpp \
|
||||
Tool.cpp \
|
||||
CheckStorageThread.cpp \
|
||||
Constant.h \
|
||||
@ -44,14 +46,15 @@ SOURCES += \
|
||||
TcpResponse.cpp \
|
||||
SerialPortTool.cpp \
|
||||
FocusWindow.cpp \
|
||||
DatabaseManager.cpp \
|
||||
TimeSlider.cpp
|
||||
DatabaseManager.cpp
|
||||
|
||||
HEADERS += \
|
||||
Widget.h \
|
||||
TcpServer.h \
|
||||
Channel.h \
|
||||
Menu.h \
|
||||
ProgressBar.h \
|
||||
Message.h \
|
||||
Tool.h \
|
||||
CheckStorageThread.h \
|
||||
Log.h \
|
||||
@ -61,11 +64,11 @@ HEADERS += \
|
||||
TcpResponse.h \
|
||||
SerialPortTool.h \
|
||||
FocusWindow.h \
|
||||
DatabaseManager.h \
|
||||
TimeSlider.h
|
||||
DatabaseManager.h
|
||||
|
||||
FORMS += \
|
||||
Menu.ui \
|
||||
ProgressBar.ui \
|
||||
Widget.ui
|
||||
|
||||
RESOURCES += \
|
||||
|
@ -28,6 +28,7 @@ SerialPortTool::SerialPortTool(QObject* parent)
|
||||
.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");
|
||||
@ -46,6 +47,10 @@ SerialPortTool::SerialPortTool(QObject* parent)
|
||||
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()
|
||||
@ -177,17 +182,17 @@ void SerialPortTool::onReayRead()
|
||||
// 返回
|
||||
emit btnReturnClicked();
|
||||
break;
|
||||
case 8:
|
||||
emit btnVolumnUpClicked();
|
||||
break;
|
||||
case 9:
|
||||
emit btnVolumnDownClicked();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPortTool::onReset()
|
||||
{
|
||||
serialPort->write(cmdMap.value(Reset));
|
||||
serialPort->flush();
|
||||
}
|
||||
|
||||
void SerialPortTool::onPlaybackStart()
|
||||
{
|
||||
serialPort->write(cmdMap.value(PlaybackStart));
|
||||
@ -235,13 +240,11 @@ 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));
|
||||
@ -296,3 +299,30 @@ void SerialPortTool::onSecondaryChannelOff()
|
||||
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();
|
||||
}
|
||||
|
@ -14,33 +14,29 @@ public:
|
||||
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);
|
||||
@ -55,8 +51,6 @@ signals:
|
||||
void btnRightClicked();
|
||||
void btnConfirmClicked();
|
||||
void btnReturnClicked();
|
||||
void btnVolumnUpClicked();
|
||||
void btnVolumnDownClicked();
|
||||
|
||||
private:
|
||||
enum CommandType {
|
||||
|
@ -23,7 +23,6 @@ void TcpConnectionHandler::onReadyRead()
|
||||
{
|
||||
bool ret = request->readFromSocket(socket);
|
||||
if (!ret) {
|
||||
response->setUrl("Unkown Url");
|
||||
response->error(request->getErrorString());
|
||||
return;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "Json.h"
|
||||
#include "Log.h"
|
||||
#include "Tool.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
@ -184,7 +183,7 @@ void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse)
|
||||
{
|
||||
QVariantMap params = request->getBodyParams();
|
||||
QString chn = params.value("interface").toString();
|
||||
if (chn != Constant::MainChannel && chn != Constant::SecondaryChannel) {
|
||||
if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) {
|
||||
Log::error("getFileList params error, error param \"interface\"");
|
||||
reponse->error("接口参数错误");
|
||||
return;
|
||||
@ -195,10 +194,9 @@ void TcpRequestHandler::getFileList(TcpRequest* request, TcpResponse* reponse)
|
||||
QList<DatabaseManager::File> fileList = db->get(channel);
|
||||
QStringList result;
|
||||
for (const DatabaseManager::File& file : fileList) {
|
||||
QVariantMap fileInfo;
|
||||
result.push_back(file.filename);
|
||||
}
|
||||
reponse->success("获取文件成功", QVariant::fromValue(result));
|
||||
reponse->success("获取文件成功", result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,7 +208,7 @@ void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse)
|
||||
QVariantMap params = request->getBodyParams();
|
||||
QString chn = params.value("interface").toString();
|
||||
QString filename = params.value("filename").toString();
|
||||
if (chn != Constant::MainChannel && chn != Constant::SecondaryChannel) {
|
||||
if (chn != Constant::MainChannel || chn != Constant::SecondaryChannel) {
|
||||
Log::error("deleteFile params error, error params \"interface\" or \"filename\"");
|
||||
reponse->error("通道参数错误");
|
||||
return;
|
||||
@ -220,24 +218,18 @@ void TcpRequestHandler::deleteFile(TcpRequest* request, TcpResponse* reponse)
|
||||
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()) {
|
||||
// 删除数据库记录
|
||||
DatabaseManager::Channel channel = chn == Constant::MainChannel
|
||||
? DatabaseManager::MainChannel
|
||||
: DatabaseManager::SecondaryChannel;
|
||||
bool ret = db->remove(channel, filename);
|
||||
if (!ret) {
|
||||
reponse->error("文件不存在");
|
||||
return;
|
||||
} else {
|
||||
video.remove();
|
||||
Log::info("remove video {}", filePath.toStdString());
|
||||
reponse->success("删除成功");
|
||||
}
|
||||
video.remove();
|
||||
Log::info("remove video {}", filePath.toStdString());
|
||||
reponse->success("删除成功");
|
||||
} else {
|
||||
Log::error("error, file: {} dont exist", filePath.toStdString());
|
||||
reponse->error("文件不存在");
|
||||
@ -323,7 +315,9 @@ void TcpRequestHandler::reboot(TcpRequest* request, TcpResponse* reponse)
|
||||
chn->stopRecord();
|
||||
}
|
||||
reponse->success("重启成功");
|
||||
qApp->quit();
|
||||
|
||||
// 退出程序,等待后台运行的shell脚本重启程序
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,7 +334,7 @@ void TcpRequestHandler::setCurrentTime(TcpRequest* request, TcpResponse* reponse
|
||||
}
|
||||
|
||||
QString time = params.value("time").toString();
|
||||
QString cmd = QString("%1 -s time \"%2\"").arg(Constant::TimeSciptPath).arg(time);
|
||||
QString cmd = QString("/link/bin/rtc -s time %1").arg(time);
|
||||
QString result = Tool::writeCom(cmd);
|
||||
// 修改成功会返回类似信息, "Tue Mar 5 15:51:18 CST 2024"
|
||||
if (result.isEmpty()) {
|
||||
|
213
TimeSlider.cpp
213
TimeSlider.cpp
@ -1,213 +0,0 @@
|
||||
#include "TimeSlider.h"
|
||||
#include <QDebug>
|
||||
#include <QStyleOption>
|
||||
#include <QTime>
|
||||
|
||||
#define MARGIN_LEFT 15 // 左边距
|
||||
#define MARGIN_RIGHT 15 // 又边距
|
||||
#define LONG_SCALE_LENGTH 10 // 长刻度的长度
|
||||
#define SHORT_SCALE_LENGTH 6 // 段刻度的长度
|
||||
#define SMALL_SCALE_COUNT 5 // 下刻度的数量
|
||||
#define TIME_BAR_HEIGHT 20 // 时间进度条高度
|
||||
|
||||
TimeSlider::TimeSlider(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setMinimumSize(QSize(100, 90));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重写绘制函数
|
||||
* @param event
|
||||
*/
|
||||
void TimeSlider::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
// 有焦点绘制绿色边框
|
||||
if (hasFocus()) {
|
||||
borderColor = QColor(15, 216, 82, opacity * 255);
|
||||
} else {
|
||||
borderColor = QColor(0, 0, 0, opacity * 255);
|
||||
}
|
||||
painter.setPen(QPen(borderColor, borderWidth));
|
||||
// 绘制背景颜色
|
||||
painter.setBrush(QColor(50, 50, 50, opacity * 255));
|
||||
painter.drawRect(rect().adjusted(borderWidth / 2, borderWidth / 2, -borderWidth, -borderWidth));
|
||||
// 绘制时间条
|
||||
painter.setPen(QPen(QColor { 255, 255, 255, opacity * 255 }, 1));
|
||||
painter.drawRect(MARGIN_LEFT, height() / 2, width() - MARGIN_LEFT - MARGIN_RIGHT, TIME_BAR_HEIGHT);
|
||||
// 绘制时间刻度
|
||||
drawTimeScale(painter);
|
||||
// 绘制当前时间
|
||||
if (curScaleVisible) {
|
||||
drawCurrentTime(painter);
|
||||
}
|
||||
// 绘制具体的时间段信息
|
||||
drawTimeSegments(painter);
|
||||
QWidget::paintEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制当前的时间
|
||||
* @param painter
|
||||
*/
|
||||
void TimeSlider::drawCurrentTime(QPainter& painter)
|
||||
{
|
||||
float x = MARGIN_LEFT + (current - min) * (width() - MARGIN_LEFT - MARGIN_LEFT) / (max - min);
|
||||
QString text = secToString(current, "hh:mm:ss");
|
||||
QFont font;
|
||||
font.setFamily("Microsoft YaHei");
|
||||
font.setPointSize(9);
|
||||
painter.setFont(font);
|
||||
QFontMetrics fm(painter.font());
|
||||
QRect textRect = fm.boundingRect(text);
|
||||
// 当时间接近24:00:00时,文字超出显示范围则把文字定在右上角
|
||||
if (x + textRect.width() >= rect().right()) {
|
||||
textRect.moveTopRight(QPoint(rect().right(), borderWidth));
|
||||
} else {
|
||||
textRect.moveTopLeft(QPoint(x, borderWidth));
|
||||
}
|
||||
if (x >= width() - MARGIN_LEFT) {
|
||||
x = width() - MARGIN_LEFT;
|
||||
}
|
||||
// 设置文字颜色位黄色以及背景为黑色
|
||||
painter.setPen(QColor(255, 248, 33, opacity * 255));
|
||||
QBrush brush(QColor(0, 0, 0, opacity * 255));
|
||||
painter.fillRect(textRect, brush);
|
||||
painter.drawText(textRect, text);
|
||||
painter.drawLine(x, borderWidth, x, height() - borderWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制时间刻度
|
||||
* @param paint
|
||||
*/
|
||||
void TimeSlider::drawTimeScale(QPainter& painter)
|
||||
{
|
||||
int scale = min;
|
||||
// 绘制刻度线
|
||||
while (scale % 3600 != 0) {
|
||||
scale++;
|
||||
}
|
||||
QFont font;
|
||||
font.setFamily("Microsoft YaHei");
|
||||
font.setPointSize(9);
|
||||
painter.setFont(font);
|
||||
// 绘制
|
||||
while (scale <= max) {
|
||||
float x = MARGIN_LEFT + (scale - min) * (width() - MARGIN_LEFT - MARGIN_RIGHT) / (max - min);
|
||||
// 整点绘制大刻度和文字
|
||||
if (scale % 3600 == 0) {
|
||||
// 绘制大刻度
|
||||
painter.drawLine(x, height() / 2 - LONG_SCALE_LENGTH, x, height() / 2);
|
||||
QString text = secToString(scale, "hh");
|
||||
QFontMetrics fm(painter.font());
|
||||
QRect textRect = fm.boundingRect(text);
|
||||
textRect.moveCenter(QPoint(x, height() / 2 - LONG_SCALE_LENGTH - textRect.height() / 2));
|
||||
painter.drawText(textRect, text);
|
||||
}
|
||||
// 绘制小刻度
|
||||
else {
|
||||
painter.drawLine(x, height() / 2 - SHORT_SCALE_LENGTH, x, height() / 2);
|
||||
}
|
||||
scale += 3600 / SMALL_SCALE_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制具体时间段的信息
|
||||
* @param painter
|
||||
*/
|
||||
void TimeSlider::drawTimeSegments(QPainter& painter)
|
||||
{
|
||||
painter.setPen(Qt::NoPen);
|
||||
for (const auto& segment : segments) {
|
||||
int endTime = segment.startTime + segment.duration;
|
||||
float startX = MARGIN_LEFT + (segment.startTime - min) * (width() - MARGIN_LEFT - MARGIN_LEFT) / (max - min);
|
||||
float endX = MARGIN_LEFT + (endTime - min) * (width() - MARGIN_LEFT - MARGIN_LEFT) / (max - min);
|
||||
if (endX >= width() - MARGIN_LEFT) {
|
||||
endX = width() - MARGIN_LEFT;
|
||||
}
|
||||
painter.setBrush(QColor(0, 255, 255, opacity * 255));
|
||||
painter.drawRect(startX, height() / 2, endX - startX, TIME_BAR_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置是否显示当前时间刻度
|
||||
* @param visible
|
||||
*/
|
||||
void TimeSlider::setCurScaleVisble(bool visible)
|
||||
{
|
||||
curScaleVisible = visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置当前的时间分片
|
||||
* @param timeSegments
|
||||
*/
|
||||
void TimeSlider::setTimeSegments(QList<TimeSegment>& segments)
|
||||
{
|
||||
this->segments = segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置当前时间,单位秒数
|
||||
* @param current
|
||||
*/
|
||||
void TimeSlider::setCurrent(int current)
|
||||
{
|
||||
this->current = current;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将当前设置为下一段
|
||||
*/
|
||||
void TimeSlider::nextSegment()
|
||||
{
|
||||
// for (auto it = segments.begin(); it != segments.end(); it++) {
|
||||
// if (it->startTime > current) {
|
||||
// current = it->startTime;
|
||||
// repaint();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将当前设置为下一段
|
||||
*/
|
||||
void TimeSlider::preSegment()
|
||||
{
|
||||
// for(auto it = segments.rbegin(); it != segments.rend(); it++){
|
||||
// if(it->startTime < current){
|
||||
// current = it->startTime;
|
||||
// repaint();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置背景色
|
||||
* @param color
|
||||
*/
|
||||
void TimeSlider::setBackgroundColor(QColor color)
|
||||
{
|
||||
backgroundColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置透明度
|
||||
* @param opa
|
||||
*/
|
||||
void TimeSlider::setOpacity(float opa)
|
||||
{
|
||||
if (opa < 0) {
|
||||
opa = 0;
|
||||
} else if (opa > 1) {
|
||||
opa = 1;
|
||||
}
|
||||
opacity = opa;
|
||||
}
|
71
TimeSlider.h
71
TimeSlider.h
@ -1,71 +0,0 @@
|
||||
/******************************************************************************
|
||||
* @file TimeSlider.h
|
||||
* @brief 自定义绘制一个时间轴控件
|
||||
* @author LuoXiang
|
||||
* @date 2024/08/28
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TIMESLIDER_H
|
||||
#define TIMESLIDER_H
|
||||
|
||||
#include <QPainter>
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
class TimeSlider : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct TimeSegment {
|
||||
int startTime; // 开始时间,转成秒数
|
||||
int duration; // 时长,秒数
|
||||
QString filename; // 当前时间片的文件名
|
||||
};
|
||||
explicit TimeSlider(QWidget* parent = nullptr);
|
||||
void setCurrent(int current);
|
||||
void setTimeSegments(QList<TimeSegment>& segments);
|
||||
void setCurScaleVisble(bool visible);
|
||||
void nextSegment();
|
||||
void preSegment();
|
||||
void setBackgroundColor(QColor color);
|
||||
void setOpacity(float opacity);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void focusInEvent(QFocusEvent* event) override
|
||||
{
|
||||
repaint();
|
||||
QWidget::focusInEvent(event);
|
||||
}
|
||||
void focusOutEvent(QFocusEvent* event) override
|
||||
{
|
||||
repaint();
|
||||
QWidget::focusInEvent(event);
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
int min = 0; // 起始时间(秒数)
|
||||
int current = 0; // 当前秒数
|
||||
int max = 24 * 60 * 60; // 终止时间(秒数)
|
||||
QList<TimeSegment> segments; // 时间片
|
||||
bool curScaleVisible = true;
|
||||
QColor backgroundColor = QColor(50, 50, 50);
|
||||
float opacity = 1.0;
|
||||
int borderWidth = 3;
|
||||
QColor borderColor;
|
||||
|
||||
private:
|
||||
void drawCurrentTime(QPainter& painter);
|
||||
void drawTimeScale(QPainter& painter);
|
||||
void drawTimeSegments(QPainter& painter);
|
||||
inline QString secToString(int sec, QString format);
|
||||
};
|
||||
|
||||
inline QString TimeSlider::secToString(int sec, QString format)
|
||||
{
|
||||
return QTime(0, 0, 0).addSecs(sec).toString(format);
|
||||
}
|
||||
|
||||
#endif // TIMESLIDER_H
|
38
Tool.cpp
38
Tool.cpp
@ -1,7 +1,4 @@
|
||||
#include "Tool.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "QTimer"
|
||||
#include "TimeSlider.h"
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
@ -140,38 +137,3 @@ double Tool::getCostTime(std::function<void(void)> callback, const char* callbac
|
||||
qDebug() << callbackName << "cast time:" << time << "ms";
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从数据库中获取某天的文件信息
|
||||
* @param chn
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
QList<TimeSlider::TimeSegment> Tool::calTimeSegments(QVariantMap params)
|
||||
{
|
||||
QList<TimeSlider::TimeSegment> result;
|
||||
DatabaseManager* db = DatabaseManager::getInstace();
|
||||
QList<DatabaseManager::File> fileList = db->get(params);
|
||||
if (fileList.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
// 构造时间片信息列表
|
||||
for (const auto& file : fileList) {
|
||||
TimeSlider::TimeSegment seg;
|
||||
QString startTime;
|
||||
QStringList timeList = file.datetime.split(" ");
|
||||
if (timeList.length() < 2) {
|
||||
return result;
|
||||
}
|
||||
seg.startTime = QTime(0, 0, 0).secsTo(QTime::fromString(timeList[1], "hh:mm:ss"));
|
||||
seg.duration = file.duration;
|
||||
seg.filename = file.filename;
|
||||
result.push_back(seg);
|
||||
}
|
||||
|
||||
// 对时间片信息进行排序
|
||||
std::sort(result.begin(), result.end(), [](const TimeSlider::TimeSegment& a, const TimeSlider::TimeSegment& b) {
|
||||
return a.startTime < b.startTime;
|
||||
});
|
||||
return result;
|
||||
}
|
3
Tool.h
3
Tool.h
@ -1,6 +1,5 @@
|
||||
#ifndef TOOL_H
|
||||
#define TOOL_H
|
||||
#include "TimeSlider.h"
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
@ -18,8 +17,6 @@ public:
|
||||
static int64_t getAvailableStorage(QString mountedPath);
|
||||
|
||||
static double getCostTime(std::function<void(void)> callback, const char* callbackName = "");
|
||||
|
||||
static QList<TimeSlider::TimeSegment> calTimeSegments(QVariantMap params);
|
||||
};
|
||||
|
||||
#endif // TOOL_H
|
||||
|
418
Widget.cpp
418
Widget.cpp
@ -7,16 +7,11 @@
|
||||
#include "TcpServer.h"
|
||||
#include "Tool.h"
|
||||
#include "ui_Widget.h"
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QDir>
|
||||
#include <QMutex>
|
||||
#include <QScrollBar>
|
||||
#include <QWaitCondition>
|
||||
|
||||
// 认为两个视频是连续的时间间隔阈值
|
||||
#define TIME_GAP_THRRSHOLD 2
|
||||
|
||||
// 多线程中使用
|
||||
QMutex mutex;
|
||||
QWaitCondition condition;
|
||||
@ -36,16 +31,12 @@ Widget::Widget(QWidget* parent)
|
||||
ui->lblTxtA->setText("未录制");
|
||||
ui->lblTxtB->setText("未录制");
|
||||
ui->recordWidget->hide();
|
||||
ui->timeSlider->hide();
|
||||
ui->timeSlider->setOpacity(0.5);
|
||||
|
||||
menu = new Menu();
|
||||
menu->hide();
|
||||
// 设置是否显示通道选择
|
||||
menu->setChannelSelectVisible(playbackMode == Constant::OneChannelPlayback);
|
||||
connect(menu, SIGNAL(btnPlaybackClicked(QVariantMap, int)), this, SLOT(onBtnPlaybackClicked(QVariantMap, int)));
|
||||
connect(menu, SIGNAL(resolutionOutAChanged(int)), this, SLOT(onResolutionOutAChanged(int)));
|
||||
connect(menu, SIGNAL(resolutionOutBChanged(int)), this, SLOT(onResolutionOutBChanged(int)));
|
||||
ui->progressBar->hide();
|
||||
|
||||
// 每5秒更新一次进度条
|
||||
progressTimer = new QTimer();
|
||||
@ -55,17 +46,13 @@ Widget::Widget(QWidget* parent)
|
||||
for (Channel* chn : channelList) {
|
||||
connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd()));
|
||||
connect(chn, SIGNAL(showRecordState(bool)), this, SLOT(onShowRecordLabel(bool)));
|
||||
connect(chn, SIGNAL(appendOneVideo()), this, SLOT(onAppendVideo()));
|
||||
// 监听输入信号的变化
|
||||
connect(chn->videoInput, &LinkObject::newEvent, [=](QString type, QVariant msg) {
|
||||
if (type == "signal") {
|
||||
QVariantMap data = msg.toMap();
|
||||
bool available = data["avalible"].toBool();
|
||||
if (available) {
|
||||
Log::info("video input {} is available",
|
||||
chn->channelName == Constant::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel);
|
||||
Log::info("video input {} is available", chn->channelName == Constant::MainChannel ? Constant::MainChannel : Constant::SecondaryChannel);
|
||||
if (chn->channelName == Constant::MainChannel) {
|
||||
serialPortTool->onMainChannelOn();
|
||||
QThread::msleep(100);
|
||||
@ -74,10 +61,7 @@ Widget::Widget(QWidget* parent)
|
||||
QThread::msleep(100);
|
||||
}
|
||||
} else {
|
||||
Log::info("video input {} is not available",
|
||||
chn->channelName == Constant::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel);
|
||||
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);
|
||||
@ -97,41 +81,29 @@ Widget::Widget(QWidget* parent)
|
||||
connect(serialPortTool, SIGNAL(btnRightClicked()), this, SLOT(onBtnRightClicked()));
|
||||
connect(serialPortTool, SIGNAL(btnConfirmClicked()), this, SLOT(onBtnConfirmClicked()));
|
||||
connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked()));
|
||||
connect(serialPortTool, SIGNAL(btnVolumnUpClicked()), this, SLOT(onBtnVolumnUpClicked()));
|
||||
connect(serialPortTool, SIGNAL(btnVolumnDownClicked()), this, SLOT(onBtnVolumnDownClicked()));
|
||||
|
||||
connect(menu, SIGNAL(curChannelChanged(QString)), this, SLOT(onCurChannelChanged(QString)));
|
||||
connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString)));
|
||||
connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickVideo(QString)));
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
delete progressTimer;
|
||||
// delete menu;
|
||||
delete menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 实时获取当前回放视频的位置
|
||||
* @brief 更新进度条
|
||||
*/
|
||||
void Widget::onProgressTimeout()
|
||||
{
|
||||
// 获取当前回放的通道名称
|
||||
QString channelName;
|
||||
// 如果时一路回放则取当前回放的时候
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
DatabaseManager::Channel curChn = static_cast<DatabaseManager::Channel>(playbackParams.value("channel", 1).toInt());
|
||||
channelName = curChn == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
}
|
||||
// 否则取主通道
|
||||
else {
|
||||
channelName = Constant::MainChannel;
|
||||
}
|
||||
Channel* chn = findChannelByName(channelName);
|
||||
Channel* chn = findChannelByName(Constant::MainChannel);
|
||||
if (chn) {
|
||||
// 获取当前播放位置,单位s
|
||||
int pos = chn->inputFile->invoke("getPosition").toInt() / 1000;
|
||||
int cur = segments[curSegmentIndex].startTime + pos;
|
||||
ui->timeSlider->setCurrent(cur);
|
||||
// 获取当前播放位置,单位ms
|
||||
int pos = chn->inputFile->invoke("getPosition").toInt();
|
||||
ui->progressBar->setCurrent(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +114,6 @@ void Widget::onBtnMenuClicked()
|
||||
{
|
||||
if (!menu->isVisible()) {
|
||||
menu->show();
|
||||
menu->moveToCenter();
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,11 +134,14 @@ void Widget::onBtnReturnClicked()
|
||||
if (chn->state != Channel::Stop) {
|
||||
chn->startPlayLive();
|
||||
serialPortTool->onPlaybackEnd();
|
||||
curPlayFilename = "";
|
||||
}
|
||||
}
|
||||
// 隐藏进度条并关闭定时器
|
||||
ui->progressBar->hide();
|
||||
progressTimer->stop();
|
||||
isPlayback = false;
|
||||
ui->timeSlider->hide();
|
||||
// 显示录制状态
|
||||
// ui->recordWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,9 +154,8 @@ void Widget::onBtnUpClicked()
|
||||
menu->move(Menu::Up);
|
||||
return;
|
||||
}
|
||||
// 时间轴选中移动到上一个视频的开始
|
||||
if (isPlayback) {
|
||||
playPreSegment();
|
||||
emit needPlayVideo("previous");
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,9 +168,8 @@ void Widget::onBtnDownClicked()
|
||||
menu->move(Menu::Down);
|
||||
return;
|
||||
}
|
||||
// 时间轴移动到下一个视频
|
||||
if (isPlayback) {
|
||||
playNextSegemnt();
|
||||
emit needPlayVideo("next");
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,10 +216,13 @@ void Widget::onBtnConfirmClicked()
|
||||
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();
|
||||
}
|
||||
@ -258,117 +233,34 @@ void Widget::onBtnConfirmClicked()
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 增大音量
|
||||
* @brief 回放视频
|
||||
*/
|
||||
void Widget::onBtnVolumnUpClicked()
|
||||
void Widget::onBtnVideoClicked(QString filename)
|
||||
{
|
||||
Channel::volumeUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 减小音量
|
||||
*/
|
||||
void Widget::onBtnVolumnDownClicked()
|
||||
{
|
||||
Channel::volumeDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 播放视频
|
||||
* @param params 参数(通道,时间)
|
||||
* @param segmentIndex 时间片索引
|
||||
*/
|
||||
void Widget::onBtnPlaybackClicked(QVariantMap params, int segmentIndex)
|
||||
{
|
||||
if (segmentIndex < 0) {
|
||||
return;
|
||||
}
|
||||
// 获取当前通道
|
||||
segments = Tool::calTimeSegments(params);
|
||||
if (segmentIndex > segments.length() - 1) {
|
||||
return;
|
||||
}
|
||||
playbackParams = params;
|
||||
curSegmentIndex = segmentIndex;
|
||||
isPlayback = true;
|
||||
// 显示时间轴
|
||||
ui->timeSlider->show();
|
||||
ui->timeSlider->setTimeSegments(segments);
|
||||
ui->timeSlider->setCurrent(segments[segmentIndex].startTime);
|
||||
|
||||
QString filename = segments[segmentIndex].filename;
|
||||
// 开始回放
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(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 {
|
||||
playTwoChannels(filename);
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
serialPortTool->onPlaybackStart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通道A分辨率修改
|
||||
* @param resolution 分辨率字符串
|
||||
*/
|
||||
void Widget::onResolutionOutAChanged(int resolution)
|
||||
void Widget::onCurChannelChanged(QString channel)
|
||||
{
|
||||
for (Channel* chn : channelList) {
|
||||
if (chn->channelName == Constant::MainChannel) {
|
||||
chn->changeOutputResolution(static_cast<Channel::Resolution>(resolution));
|
||||
switch (resolution) {
|
||||
case 0:
|
||||
setFixedSize(1920, 1080);
|
||||
break;
|
||||
case 1:
|
||||
setFixedSize(1600, 1200);
|
||||
break;
|
||||
case 2:
|
||||
setFixedSize(1280, 1024);
|
||||
break;
|
||||
case 3:
|
||||
setFixedSize(1024, 768);
|
||||
break;
|
||||
case 4:
|
||||
setFixedSize(800, 600);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
menu->restartUI();
|
||||
menu->update();
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通道B分辨率修改
|
||||
* @param resolution
|
||||
*/
|
||||
void Widget::onResolutionOutBChanged(int resolution)
|
||||
{
|
||||
for (Channel* chn : channelList) {
|
||||
if (chn->channelName == Constant::SecondaryChannel) {
|
||||
chn->changeOutputResolution(static_cast<Channel::Resolution>(resolution));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onResolutionInAChanged(int width, int height)
|
||||
{
|
||||
for (Channel* chn : channelList) {
|
||||
if (chn->channelName == Constant::MainChannel) {
|
||||
chn->changeInputResolution(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onResolutionInBChanged(int width, int height)
|
||||
{
|
||||
for (Channel* chn : channelList) {
|
||||
if (chn->channelName == Constant::SecondaryChannel) {
|
||||
chn->changeInputResolution(width, height);
|
||||
}
|
||||
}
|
||||
curSelectChannel = channel;
|
||||
Log::info("channel switch, current channel:", channel.toStdString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -376,11 +268,7 @@ void Widget::onResolutionInBChanged(int width, int height)
|
||||
*/
|
||||
void Widget::playOneChannel(QString filename)
|
||||
{
|
||||
// 获取当前回放的通道
|
||||
QString curPlayChannel = menu->getCurPlayChannel() == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curPlayChannel).arg(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();
|
||||
@ -388,14 +276,26 @@ void Widget::playOneChannel(QString filename)
|
||||
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();
|
||||
@ -415,6 +315,12 @@ void Widget::playTwoChannels(QString 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();
|
||||
@ -423,12 +329,17 @@ void Widget::playTwoChannels(QString filename)
|
||||
}
|
||||
ui->recordWidget->hide();
|
||||
} else {
|
||||
ui->progressBar->hide();
|
||||
ui->recordWidget->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curPlayFilename = filename;
|
||||
curPlayChannel = Constant::MainChannel;
|
||||
isPlayback = true;
|
||||
// 全局保存正在播放的视频的文件名
|
||||
|
||||
// 全局保存正在播放的视频
|
||||
mutex.lock();
|
||||
curFilename = filename;
|
||||
condition.wakeAll();
|
||||
@ -442,86 +353,18 @@ void Widget::seek(QString type)
|
||||
{
|
||||
if (!isPlayback)
|
||||
return;
|
||||
QString channelName;
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
DatabaseManager::Channel curChn = static_cast<DatabaseManager::Channel>(playbackParams.value("channel", 1).toInt());
|
||||
channelName = curChn == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
} else {
|
||||
channelName = Constant::MainChannel;
|
||||
}
|
||||
Channel* chn = findChannelByName(channelName);
|
||||
int pos;
|
||||
// 获取当前播放的位置
|
||||
if (chn) {
|
||||
pos = chn->inputFile->invoke("getPosition").toInt() / 1000;
|
||||
}
|
||||
if (type == "forward") {
|
||||
pos += 10;
|
||||
// 目标位置超过当前视频的时长
|
||||
if (pos > segments[curSegmentIndex].duration) {
|
||||
// 如果是最后一个视频,则跳转到视频最后为止
|
||||
if (curSegmentIndex == segments.length() - 1) {
|
||||
pos = segments[curSegmentIndex].duration;
|
||||
}
|
||||
// 如果不是最后一个视频
|
||||
else {
|
||||
int gap = segments[curSegmentIndex + 1].startTime
|
||||
- segments[curSegmentIndex].startTime
|
||||
- segments[curSegmentIndex].duration;
|
||||
// 视频是连续的就跳转到响应为止,认为连续的条件是间隔小于2S
|
||||
if (gap <= TIME_GAP_THRRSHOLD) {
|
||||
pos = pos - segments[curSegmentIndex].duration - gap;
|
||||
curSegmentIndex++;
|
||||
QString filename = segments[curSegmentIndex].filename;
|
||||
// 开始回放
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
}
|
||||
// 视频不是连续的
|
||||
else {
|
||||
pos = segments[curSegmentIndex].duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
pos -= 10;
|
||||
// 目标位置小于0
|
||||
if (pos < 0) {
|
||||
if (curSegmentIndex == 0) {
|
||||
pos = 0;
|
||||
} else {
|
||||
int gap = segments[curSegmentIndex].startTime
|
||||
- segments[curSegmentIndex - 1].startTime
|
||||
- segments[curSegmentIndex - 1].duration;
|
||||
// 视频是连续的
|
||||
if (gap <= TIME_GAP_THRRSHOLD) {
|
||||
pos = segments[curSegmentIndex - 1].duration + gap + pos;
|
||||
curSegmentIndex--;
|
||||
QString filename = segments[curSegmentIndex].filename;
|
||||
// 重新回放
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
}
|
||||
// 视频不是连续的
|
||||
else {
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Channel* chn : channelList) {
|
||||
if (chn->state == Channel::Playback) {
|
||||
chn->inputFile->invoke("seek", pos * 1000);
|
||||
Log::info("{} seek {} 10s", chn->channelName.toStdString(), type.toStdString());
|
||||
if (chn->state == Channel::Pause || chn->state == Channel::Playback) {
|
||||
if (type == "forward") {
|
||||
chn->forward();
|
||||
serialPortTool->onFoward();
|
||||
} else {
|
||||
chn->back();
|
||||
serialPortTool->onBack();
|
||||
}
|
||||
|
||||
if (chn->channelName == Constant::MainChannel)
|
||||
ui->progressBar->showMax();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -531,8 +374,6 @@ void Widget::seek(QString type)
|
||||
*/
|
||||
void Widget::onPlayEnd()
|
||||
{
|
||||
// 停下回放计时器
|
||||
progressTimer->stop();
|
||||
// 当两路回放时,只处理一次槽函数
|
||||
if (playbackMode == Constant::TwoChannelPlayback) {
|
||||
LinkObject* file = static_cast<LinkObject*>(sender());
|
||||
@ -544,23 +385,7 @@ void Widget::onPlayEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果时列表最后一个视频则显示播放结束
|
||||
if (curSegmentIndex == segments.length() - 1) {
|
||||
for (Channel* chn : channelList) {
|
||||
chn->showFinishPromot();
|
||||
}
|
||||
}
|
||||
// 不是列表最后一个就播放下一个视频
|
||||
else {
|
||||
curSegmentIndex++;
|
||||
ui->timeSlider->setCurrent(segments[curSegmentIndex].startTime);
|
||||
QString filename = segments[curSegmentIndex].filename;
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
}
|
||||
emit needPlayVideo("next");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -601,82 +426,3 @@ Channel* Widget::findChannelByName(QString name)
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 播放下一个视频片段
|
||||
*/
|
||||
void Widget::playNextSegemnt()
|
||||
{
|
||||
if (curSegmentIndex < segments.length() - 1) {
|
||||
curSegmentIndex++;
|
||||
// 设置时间轴指针的位置
|
||||
int cur = segments[curSegmentIndex].startTime;
|
||||
ui->timeSlider->setCurrent(cur);
|
||||
// 跳转到下一个视频
|
||||
QString filename = segments[curSegmentIndex].filename;
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
Log::info("play next segment, filename: {}", filename.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 播放上一个视频片段
|
||||
*/
|
||||
void Widget::playPreSegment()
|
||||
{
|
||||
if (curSegmentIndex > 0) {
|
||||
curSegmentIndex--;
|
||||
// 设置时间轴指针的位置
|
||||
int cur = segments[curSegmentIndex].startTime;
|
||||
ui->timeSlider->setCurrent(cur);
|
||||
// 跳转到下一个视频
|
||||
QString filename = segments[curSegmentIndex].filename;
|
||||
if (playbackMode == Constant::OneChannelPlayback) {
|
||||
playOneChannel(filename);
|
||||
} else {
|
||||
playTwoChannels(filename);
|
||||
}
|
||||
Log::info("play previous segment, filename: {}", filename.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 一个录制片段完成的槽函数
|
||||
*/
|
||||
void Widget::onAppendVideo()
|
||||
{
|
||||
if (!isPlayback) {
|
||||
return;
|
||||
}
|
||||
Channel* chn = static_cast<Channel*>(sender());
|
||||
// 两路回放需要是主通道
|
||||
if (playbackMode == Constant::TwoChannelPlayback) {
|
||||
if (chn->channelName != Constant::MainChannel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 一路回放需要回放通道和录制通道一致
|
||||
else {
|
||||
DatabaseManager::Channel c = static_cast<DatabaseManager::Channel>(playbackParams.value("channel", 1).toInt());
|
||||
QString channelName = c == DatabaseManager::MainChannel
|
||||
? Constant::MainChannel
|
||||
: Constant::SecondaryChannel;
|
||||
if (chn->channelName != channelName) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 刷新时间轴中时间片的显示
|
||||
segments = Tool::calTimeSegments(playbackParams);
|
||||
ui->timeSlider->setTimeSegments(segments);
|
||||
}
|
||||
|
||||
void Widget::update()
|
||||
{
|
||||
QRect deskRect = QApplication::desktop()->availableGeometry();
|
||||
qDebug() << "desktop rect:" << deskRect;
|
||||
QWidget::update();
|
||||
}
|
||||
|
36
Widget.h
36
Widget.h
@ -3,7 +3,8 @@
|
||||
|
||||
#include "Channel.h"
|
||||
#include "Menu.h"
|
||||
#include "TimeSlider.h"
|
||||
#include "Message.h"
|
||||
#include "ProgressBar.h"
|
||||
#include <QDir>
|
||||
#include <QMap>
|
||||
#include <QTimer>
|
||||
@ -22,13 +23,10 @@ public:
|
||||
signals:
|
||||
void needPlayVideo(QString types);
|
||||
|
||||
public slots:
|
||||
void update();
|
||||
|
||||
private slots:
|
||||
void onProgressTimeout();
|
||||
void onPlayEnd();
|
||||
void onShowRecordLabel(bool show);
|
||||
void onAppendVideo();
|
||||
|
||||
// 按键操作。上下左右确认返回
|
||||
void onBtnMenuClicked();
|
||||
@ -38,37 +36,27 @@ public slots:
|
||||
void onBtnRightClicked();
|
||||
void onBtnConfirmClicked();
|
||||
void onBtnReturnClicked();
|
||||
void onBtnVolumnUpClicked();
|
||||
void onBtnVolumnDownClicked();
|
||||
|
||||
// 播放视频
|
||||
void onBtnPlaybackClicked(QVariantMap params, int segmentIndex);
|
||||
|
||||
// 分辨率更改
|
||||
void onResolutionOutAChanged(int resolution);
|
||||
void onResolutionOutBChanged(int resolution);
|
||||
|
||||
void onResolutionInAChanged(int width, int height);
|
||||
void onResolutionInBChanged(int width, int height);
|
||||
void onBtnVideoClicked(QString filename);
|
||||
void onCurChannelChanged(QString channel);
|
||||
|
||||
private:
|
||||
Ui::Widget* ui;
|
||||
|
||||
Menu* menu; // 菜单指针
|
||||
QTimer* progressTimer;
|
||||
bool isPlayback = false;
|
||||
QString curPlayChannel;
|
||||
QString curSelectChannel;
|
||||
QString curPlayFilename;
|
||||
|
||||
bool isPlayback = false; // 是否在回放
|
||||
QTimer* progressTimer; // 查询播放进度的定时器
|
||||
QList<TimeSlider::TimeSegment> segments; // 当天回放的时间段
|
||||
int curSegmentIndex = 0; // 当前回放的时间段
|
||||
QVariantMap playbackParams; // 回放参数(通道和时间)
|
||||
Menu* menu;
|
||||
|
||||
private:
|
||||
void seek(QString type);
|
||||
void playOneChannel(QString filename);
|
||||
void playTwoChannels(QString filename);
|
||||
void playNextSegemnt();
|
||||
void playPreSegment();
|
||||
Channel* findChannelByName(QString name);
|
||||
};
|
||||
|
||||
#endif // WIDG_H
|
||||
#endif // WIDG_H
|
||||
|
@ -217,7 +217,7 @@
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="TimeSlider" name="timeSlider" native="true"/>
|
||||
<widget class="ProgressBar" name="progressBar" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@ -226,9 +226,9 @@
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TimeSlider</class>
|
||||
<class>ProgressBar</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">TimeSlider.h</header>
|
||||
<header location="global">ProgressBar.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
126
main.cpp
126
main.cpp
@ -20,8 +20,9 @@ TcpServer* server;
|
||||
SerialPortTool* serialPortTool;
|
||||
// 数据库管理
|
||||
DatabaseManager* db;
|
||||
// 硬盘检测线程
|
||||
CheckStorageThread* thread;
|
||||
// 视频输出通道
|
||||
LinkObject* vo;
|
||||
LinkObject* vo1;
|
||||
|
||||
// 通道列表
|
||||
QList<Channel*> channelList;
|
||||
@ -29,6 +30,8 @@ QList<Channel*> channelList;
|
||||
Constant::RecordMode recordMode;
|
||||
// 回放模式
|
||||
Constant::PlaybackMode playbackMode;
|
||||
QString mainChannelProtocol;
|
||||
QString secondaryChannelProtocol;
|
||||
|
||||
/**
|
||||
* @brief 加载配置文件
|
||||
@ -47,13 +50,14 @@ bool loadConfiguration(QString path)
|
||||
QVariantList list = config["interface"].toList();
|
||||
// 初始化通道
|
||||
for (int i = 0; i < list.count(); i++) {
|
||||
Channel* chn = new Channel();
|
||||
QVariantMap cfg = list.at(i).toMap();
|
||||
QString channelName = cfg["name"].toString();
|
||||
if (channelName.isEmpty()) {
|
||||
return false;
|
||||
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 output = cfg["output"].toMap();
|
||||
Channel* chn = new Channel(channelName, output);
|
||||
|
||||
QVariantMap encV = cfg["encV"].toMap();
|
||||
chn->videoEncoderParams = encV;
|
||||
@ -63,6 +67,7 @@ bool loadConfiguration(QString path)
|
||||
|
||||
chn->pushCode = cfg["pushCode"].toString();
|
||||
|
||||
chn->init();
|
||||
channelList.push_back(chn);
|
||||
}
|
||||
return true;
|
||||
@ -81,14 +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);
|
||||
serialPortTool->onRecordStart();
|
||||
QThread::msleep(100);
|
||||
// serialPortTool->onLoopOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,19 +105,36 @@ void startRecord()
|
||||
chn->startRecord();
|
||||
serialPortTool->onRecordStart();
|
||||
QThread::msleep(100);
|
||||
// serialPortTool->onLoopOff();
|
||||
// QThread::msleep(100);
|
||||
}
|
||||
}
|
||||
// 无录制
|
||||
else {
|
||||
// 打开环路灯
|
||||
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[])
|
||||
{
|
||||
// qDebug() << (R"(
|
||||
// ____ _ _____
|
||||
// / ___|| |__ __ _ _ __ | ___|__ _ __ __ _
|
||||
// \___ \| '_ \ / _` | '_ \| |_ / _ \ '_ \ / _` |
|
||||
// ___) | | | | (_| | | | | _| __/ | | | (_| |
|
||||
// |____/|_| |_|\__,_|_| |_|_| \___|_| |_|\__, |
|
||||
// |___/ )");
|
||||
// std::atexit(resetLight);
|
||||
// 初始化日志
|
||||
Log::init();
|
||||
@ -120,36 +144,84 @@ int main(int argc, char* argv[])
|
||||
Log::error("Link init failed, exit");
|
||||
return 0;
|
||||
}
|
||||
// 在初始化QApplication之前初始化视频输出和linuxfb
|
||||
// 否则不能显示qt的ui
|
||||
|
||||
// HDMI-OUT0视频输出,只将ui输出在0口
|
||||
vo = Link::create("OutputVo");
|
||||
QVariantMap dataVo;
|
||||
dataVo["ui"] = true;
|
||||
dataVo["type"] = "hdmi";
|
||||
vo->start(dataVo);
|
||||
|
||||
// HDMI-OUT1视频输出
|
||||
vo1 = Link::create("OutputVo");
|
||||
QVariantMap dataVo1;
|
||||
dataVo1["ui"] = false;
|
||||
dataVo1["type"] = "bt1120";
|
||||
vo1->start(dataVo1);
|
||||
|
||||
/**
|
||||
* 后续可能需要进行修改**************************
|
||||
*/
|
||||
|
||||
// HDMI-OUT1口特殊设置
|
||||
static int lastNorm = 0;
|
||||
int norm = 0;
|
||||
int ddr = 0;
|
||||
// 获取到设置的输出分辨率
|
||||
QString str = "1080P60";
|
||||
if (str == "1080P60")
|
||||
norm = 9;
|
||||
else if (str == "1080P50")
|
||||
norm = 10;
|
||||
else if (str == "1080P30")
|
||||
norm = 12;
|
||||
else if (str == "720P60")
|
||||
norm = 5;
|
||||
else if (str == "720P50")
|
||||
norm = 6;
|
||||
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 = cmd.sprintf("insmod /ko/extdrv/hi_lt8618sx_lp.ko norm=%d USE_DDRCLK=%d", norm, ddr);
|
||||
system(cmd.toLatin1().data());
|
||||
}
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
// 初始化配置文件, 需要在QApplication之后
|
||||
if (!loadConfiguration(Constant::ConfigurationPath)) {
|
||||
Log::error("load configuration failed, exit...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
// 初始化通道配置,需要在QApplication之后进行
|
||||
for (const auto& chn : channelList) {
|
||||
chn->init();
|
||||
}
|
||||
|
||||
// 打开串口
|
||||
serialPortTool = new SerialPortTool();
|
||||
serialPortTool->open();
|
||||
|
||||
// setChannelProtocol();
|
||||
serialPortTool->onPowerOn(); // 打开电源灯
|
||||
QThread::msleep(100);
|
||||
|
||||
// 开启Tcp服务
|
||||
// server = new TcpServer();
|
||||
// server->listen();
|
||||
server = new TcpServer();
|
||||
server->listen();
|
||||
|
||||
// qt界面
|
||||
Widget w;
|
||||
w.show();
|
||||
|
||||
// 硬盘检测线程,检测硬盘容量
|
||||
thread = new CheckStorageThread();
|
||||
CheckStorageThread* thread = new CheckStorageThread();
|
||||
thread->start();
|
||||
QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull()), Qt::QueuedConnection);
|
||||
QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull()), Qt::QueuedConnection);
|
||||
QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull()));
|
||||
QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull()));
|
||||
Log::info("start storage check thread...");
|
||||
|
||||
// 开始录制
|
||||
|
Loading…
Reference in New Issue
Block a user