添加修改输出分辨率并删除无用代码

This commit is contained in:
zc 2024-12-23 11:51:48 -08:00
parent 2782c6867c
commit ad225bfee3
23 changed files with 1807 additions and 1298 deletions

View File

@ -22,26 +22,40 @@ int Channel::maxGian = 12;
int Channel::minGain = -30;
int Channel::curGain = 0;
extern LinkObject* vo;
extern LinkObject* vo1;
extern DatabaseManager* db;
Channel::Channel(QObject* parent)
: QObject(parent)
{
videoInput = nullptr;
videoOutput = nullptr;
audioInput = nullptr;
audioOutput = nullptr;
videoEncoder = nullptr;
audioEncoder = nullptr;
record = nullptr;
rtsp = nullptr;
inputFile = nullptr;
videoDecoder = nullptr;
audioDecoder = nullptr;
image = Link::create("InputImage");
void configureOutput2(QString resolutionStr);
Channel::Channel(const QString& name, const QVariantMap& params, QObject* parent)
: channelName(name)
, videoOutputParams(params)
, QObject(parent)
{
videoOutput = Link::create("OutputVo");
videoOutput->start(videoOutputParams);
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;
@ -49,7 +63,7 @@ Channel::Channel(QObject* parent)
dataIn["channels"] = 2;
lineIn->start(dataIn);
}
if (resample = nullptr) {
if (resample == nullptr) {
resample = Link::create("Resample");
resample->start();
lineIn->linkA(resample);
@ -74,33 +88,9 @@ Channel::Channel(QObject* parent)
rtspServer = Link::create("Rtsp");
rtspServer->start();
}
}
image = Link::create("InputImage");
Channel::~Channel()
{
}
/**
* @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);
@ -115,6 +105,9 @@ void Channel::init()
videoInput->start(dataVi);
videoInput->linkV(overlay)->linkV(videoOutput);
// 通道音频输出
audioOutput = Link::create("OutputAo");
// 通道音频输入
audioInput = Link::create("InputAi");
QVariantMap dataAi;
@ -141,7 +134,7 @@ void Channel::init()
dataMp4["segmentDuration"] = duration;
record->setData(dataMp4);
videoInput->linkV(videoEncoder)->linkV(record);
audioInput->linkV(audioEncoder)->linkV(record);
audioInput->linkA(audioEncoder)->linkV(record);
resample->linkA(audioEncoder)->linkA(record);
connect(record, SIGNAL(newEvent(QString, QVariant)), this, SLOT(onNewEvent(QString, QVariant)));
@ -154,6 +147,18 @@ 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;
@ -188,6 +193,26 @@ 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
*/
@ -220,37 +245,10 @@ void Channel::onNewEvent(QString msg, QVariant data)
// 重新设置视频的录制起始时间
curTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
segmentId = data.toInt();
// 修改文件名本次录制起始时间_%d ==> 当前视频录制起始时间
QString filename = QString("%1_%2.mp4").arg(startTime).arg(segmentId - 1);
QString newFilename = QString("%1/%2/%3.mp4").arg(Constant::VideoPath).arg(channelName).arg(datetime);
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(channelName).arg(filename);
QFile file(path);
if (!file.rename(newFilename)) {
Log::error("rename file name failed in function onNewEvent, old filename: {}, target filename: {} , channel name: {},reason: {}",
path.toStdString(),
newFilename.toStdString(),
channelName.toStdString(),
file.errorString().toStdString());
return;
}
// 将录制完的文件信息保存到数据库
DatabaseManager::File fileInfo;
fileInfo.channel = channelName == Constant::MainChannel
? DatabaseManager::MainChannel
: DatabaseManager::SecondaryChannel;
fileInfo.datetime = QDateTime::fromString(datetime, "yyyyMMddhhmmss").toString("yyyy-MM-dd hh:mm:ss");
fileInfo.filename = QString("%1.mp4").arg(datetime);
if (db->insert(fileInfo)) {
Log::info("insert one record into database success, name: {}, channel: {}",
fileInfo.filename.toStdString(),
channelName.toStdString());
} else {
Log::error("insert one record into database failed, name: {}, channel: {}",
fileInfo.filename.toStdString(),
channelName.toStdString());
}
// 更新当前录制录制视频的时间
emit appendOneVideo(channelName);
// 异步执行保存文件信息的函数
QTimer::singleShot(3000, this, [=]() {
saveVideoInfo(datetime, segmentId - 1);
});
}
}
@ -261,39 +259,12 @@ void Channel::stopRecord()
{
Log::info("{} stop recording...", channelName.toStdString());
record->stop(true);
// 修改文件名本次录制起始时间_%d ==> 当前视频录制起始时间
QString filename = QString("%1_%2.mp4").arg(startTime).arg(segmentId);
QString newFilename = QString("%1/%2/%3.mp4").arg(Constant::VideoPath).arg(channelName).arg(curTime);
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(channelName).arg(filename);
QFile file(path);
if (!file.rename(newFilename)) {
Log::error("rename file name failed in function onNewEvent, old filename: {}, target filename: {} , channel name: {},reason: {}",
path.toStdString(),
newFilename.toStdString(),
channelName.toStdString(),
file.errorString().toStdString());
return;
}
// 将录制文件的信息存入数据库
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);
if (db->insert(fileInfo)) {
Log::info("insert one record into database success, name: {}, channel: {}",
fileInfo.filename.toStdString(),
channelName.toStdString());
} else {
Log::error("insert one record into database failed, name: {}, channel: {}",
fileInfo.filename.toStdString(),
channelName.toStdString());
}
// 更新当前录制录制视频的时间
emit appendOneVideo(channelName);
// 异步执行保存文件信息的函数
QTimer::singleShot(1000, this, [=]() {
saveVideoInfo(curTime, segmentId);
});
// 重置水印和时间
overlay->setData(norecordOverlay);
// 重置时间
startTime = "";
curTime = "";
}
@ -371,25 +342,12 @@ void Channel::startPlayLive()
}
/**
* @brief 退10s
* @brief
* @param pos
*/
void Channel::back()
void Channel::seek(int 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);
inputFile->invoke("seek", pos);
}
/**
@ -481,3 +439,79 @@ 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());
}
}

View File

@ -16,18 +16,31 @@ public:
Error,
Finish
};
explicit Channel(QObject* parent = nullptr);
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();
void init();
// 输出分辨率
void changeOutputResolution(Resolution resolution);
void changeInputResolution(int width, int height);
// 录制
void startRecord();
void stopRecord();
// 回放
bool startPlayback(QString path);
void forward();
void back();
void seek(int pos);
void togglePause();
void startPlayLive();
void showFinishPromot();
@ -40,11 +53,16 @@ public:
public:
QString channelName;
LinkObject* videoInput;
LinkObject* videoEncoder;
QVariantMap videoEncoderParams;
LinkObject* videoOutput;
// 视频输入输出
LinkObject* videoInput = nullptr;
LinkObject* videoOutput = nullptr;
QVariantMap videoOutputParams;
// 视频编码
LinkObject* videoEncoder = nullptr;
QVariantMap videoEncoderParams;
// 外接音频输入输出
static LinkObject* lineIn; // 外部音频输入
static LinkObject* resample; // 重采样
static LinkObject* lineOut; // 外部音频输出
@ -54,39 +72,51 @@ public:
static int minGain; // 最小增益
static int curGain; // 当前增益
LinkObject* audioInput; // 通道音频输入
LinkObject* audioOutput; // 通道音频输入
LinkObject* audioEncoder; // 音频编码器
// 通道音频输入输出
LinkObject* audioInput = nullptr; // 通道音频输入
LinkObject* audioOutput = nullptr; // 通道音频输入
LinkObject* audioEncoder = nullptr; // 音频编码器
QVariantMap audioEncoderParams; // 编码参数
LinkObject* record;
int duration = 1 * 60 * 1000; // 单个视频时长
// 视频录制
LinkObject* record = nullptr;
LinkObject* calDuration = nullptr;
LinkObject* calAudioDecoder = nullptr;
LinkObject* calVideoDecoder = nullptr;
int duration = 10 * 60 * 1000; // 单个视频时长
bool isRecord = false;
QString startTime; // 本次录制文件的开始时间
QString curTime; // 当前录制文件的开始时间
int segmentId = 0;
LinkObject* overlay; // 水印,提示是否在录制视频
int segmentId = 0; // 分片录制的id
// 水印
LinkObject* overlay = nullptr; // 水印,提示是否在录制视频
QVariantMap recordOverlay; // 录制状态下的水印参数
QVariantMap norecordOverlay; // 非录制状态下的水印参数
// 视频回放
int playbackDuration = 0; // 当前播放视频的时长单位ms
LinkObject* inputFile;
LinkObject* videoDecoder;
LinkObject* audioDecoder;
LinkObject* image;
LinkObject* inputFile = nullptr;
LinkObject* videoDecoder = nullptr;
LinkObject* audioDecoder = nullptr;
LinkObject* image = nullptr;
PlaybackState state = Stop;
// 视频推流
static LinkObject* rtspServer;
LinkObject* rtsp;
LinkObject* rtsp = nullptr;
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(QString channelName);
void appendOneVideo();
private:
void loadOverlayConfig();

View File

@ -17,7 +17,8 @@ extern QMutex mutex;
extern QWaitCondition condition;
extern DatabaseManager* db;
CheckStorageThread::CheckStorageThread()
CheckStorageThread::CheckStorageThread(QObject* parent)
: QThread(parent)
{
}

View File

@ -6,7 +6,7 @@
class CheckStorageThread : public QThread {
Q_OBJECT
public:
CheckStorageThread();
CheckStorageThread(QObject* parent = nullptr);
signals:
void diskWillFull(); // 磁盘空间不足

View File

@ -66,10 +66,11 @@ void DatabaseManager::close()
bool DatabaseManager::insert(File file)
{
QSqlQuery query;
query.prepare("insert into file (channel, datetime, filename) values (?, ?, ?)");
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);
if (query.exec()) {
return true;
} else {
@ -88,7 +89,7 @@ QList<DatabaseManager::File> DatabaseManager::get(QVariantMap params)
{
QList<DatabaseManager::File> result;
QSqlQuery query;
QString sql = "select * from file where channel=? and datetime like \'%1\'";
QString sql = "select * from file where channel=? and datetime like ?";
QString year = params.value("year").toString();
QString month = params.value("month").toString();
QString day = params.value("day").toString();
@ -99,7 +100,7 @@ QList<DatabaseManager::File> DatabaseManager::get(QVariantMap params)
}
query.prepare(sql);
query.bindValue(0, chn);
query.bindValue(1, QString("%1-%2-%3%"));
query.bindValue(1, QString("%1-%2-%3%").arg(year).arg(month).arg(day));
if (query.exec()) {
while (query.next()) {
DatabaseManager::File file;
@ -107,13 +108,14 @@ QList<DatabaseManager::File> DatabaseManager::get(QVariantMap params)
file.channel = static_cast<DatabaseManager::Channel>(query.value("channel").toInt());
file.datetime = query.value("datetime").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().databaseText().toStdString() + query.lastError().driverText().toStdString());
}
Log::info("record of one day: {}", result.length());
// Log::info("record of one day: {}", result.length());
return result;
}
@ -136,6 +138,7 @@ QList<DatabaseManager::File> DatabaseManager::get(DatabaseManager::Channel chn)
file.channel = static_cast<DatabaseManager::Channel>(query.value("channel").toInt());
file.datetime = query.value("datetime").toString();
file.filename = query.value("filename").toString();
file.duration = query.value("duration").toInt();
result.push_back(file);
}
} else {
@ -159,6 +162,7 @@ QList<DatabaseManager::File> DatabaseManager::getTopTwo()
file.channel = static_cast<DatabaseManager::Channel>(query.value("channel").toInt());
file.datetime = query.value("datetime").toString();
file.filename = query.value("filename").toString();
file.duration = query.value("duration").toInt();
result.push_back(file);
}
} else {
@ -190,7 +194,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;
}
@ -206,11 +210,11 @@ QStringList DatabaseManager::getAllMonths(Channel chn, QString year)
query.prepare(R"(
select distinct strftime('%m', datetime) as month
from file
where channel = ? and strftime('%Y', datetime) = '?'
where channel = ? and strftime('%Y', datetime) = ?
order by month
)");
query.bindValue(0, chn);
query.bindValue(1, year);
query.addBindValue(chn);
query.addBindValue(year);
if (query.exec()) {
while (query.next()) {
QString month = query.value(0).toString();
@ -218,9 +222,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().databaseText().toStdString() + query.lastError().driverText().toStdString());
}
Log::info("number of month: {}", result.length());
// Log::info("number of month: {}", result.length());
return result;
}
@ -238,8 +242,8 @@ QStringList DatabaseManager::getAllDays(Channel chn, QString year, QString month
select distinct strftime('%d', datetime) as day
from file
where channel = ?
and strftime('%Y', datetime) = '?'
and strftime('%m', datetime) = '?'
and strftime('%Y', datetime) = ?
and strftime('%m', datetime) = ?
order by day
)");
query.bindValue(0, chn);
@ -252,9 +256,9 @@ 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().databaseText().toStdString() + query.lastError().driverText().toStdString());
}
Log::info("number of day: {}", result.length());
// Log::info("number of day: {}", result.length());
return result;
}

View File

@ -15,6 +15,7 @@ public:
Channel channel; // 通道
QString datetime; // 时间 yyyy-MM-dd hh:mm:ss
QString filename; // 文件名
int duration; // 时间
};
static DatabaseManager* getInstace();
~DatabaseManager();

400
Menu.cpp
View File

@ -1,16 +1,17 @@
#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>
#define CONTENT_ROW 6 // 列表行
#define CONTENT_COLUMN 6 // 列表列
#define CONTENT_CELL_HEIGHT 56 // 单元格高度
extern QList<Channel*> channelList;
Menu::Menu(QWidget* parent)
: QWidget(parent)
@ -25,30 +26,36 @@ 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;
curPlayChannel = DatabaseManager::MainChannel;
db = DatabaseManager::getInstace();
if (!db->open())
return;
// 设置ScrollArea为栅格布局
QGridLayout* layout = new QGridLayout(ui->scrollArea);
ui->scrollAreaWidgetContents->setLayout(layout);
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();
}
Menu::~Menu()
@ -56,16 +63,6 @@ Menu::~Menu()
delete ui;
}
/**
* @brief show方法
*/
void Menu::show()
{
QWidget::show();
renderComboBoxYear();
getContents();
}
/**
* @brief
* @param visible
@ -125,71 +122,6 @@ void Menu::renderComboBoxDay()
ui->cmbDay->setCurrentIndex(0);
}
/**
* @brief
*/
void Menu::getContents()
{
QVariantMap params;
params["channel"] = curSelectChannel;
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++) {
// 文件名格式: hhmmss只将时分秒显示到界面上
DatabaseManager::File file = contentList.at(i);
QString text = QDateTime::fromString(file.datetime, "yyyy-MM-dd hh:mm:ss").toString("hh:mm:ss");
QPushButton* btn = new QPushButton(text, 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));
if (file.filename == curPlayFilename) {
btn->setChecked(true);
btn->setFocus();
}
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
@ -197,30 +129,51 @@ void Menu::renderContents()
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);
@ -236,141 +189,64 @@ void Menu::move(Direction direction)
*/
void Menu::confirm()
{
int index = ui->stackedWidget->currentIndex();
QWidget* focusWidget = QApplication::focusWidget();
switch (index) {
// 通道设置界面
case 0: {
// 当前操作的是按钮
if (strcmp(focusWidget->metaObject()->className(), "QPushButton") == 0) {
QPushButton* btn = qobject_cast<QPushButton*>(focusWidget);
btn->setChecked(true);
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();
}
break;
}
// 回放界面
case 1: {
// 通道选择时按下确认
if (focusWidget == ui->btn_channel_1 || focusWidget == ui->btn_channel_2) {
QPushButton* btn = qobject_cast<QPushButton*>(focusWidget);
// 选择通道
else if (btn == ui->btn_channel_1 || btn == ui->btn_channel_2) {
btn->setChecked(true);
if (btn == ui->btn_channel_1) {
curSelectChannel = DatabaseManager::MainChannel;
} else {
curSelectChannel = DatabaseManager::SecondaryChannel;
}
curSelectChannel = btn == ui->btn_channel_1 ? DatabaseManager::MainChannel
: DatabaseManager::SecondaryChannel;
renderComboBoxYear();
}
// 下拉框未展开时按下确认
}
}
// 当前操作下拉框
else if (strcmp(focusWidget->metaObject()->className(), "QComboBox") == 0) {
QComboBox* cmb = qobject_cast<QComboBox*>(focusWidget);
cmb->showPopup();
}
// 下拉框展开时按下确认
else if (strcmp(focusWidget->metaObject()->className(), "QListView") == 0) {
} 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());
QListView* listView = static_cast<QListView*>(focusWidget);
QComboBox* cmb = static_cast<QComboBox*>(listView->parent()->parent());
if (cmb) {
cmb->setCurrentIndex(listView->currentIndex().row());
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);
// 记录当前正在回放的通道和文件名
curPlayFilename = filename;
curPlayChannel = curSelectChannel;
}
// 确认按钮按下确认
else if (focusWidget->objectName() == "btn_done") {
getContents();
}
break;
}
default:
break;
}
}
/**
* @brief
*/
void Menu::clickPreOrNext(QString type)
{
// 重新获取当前正在回放通道的视频
// 选中进度条
else if (focusWidget->objectName() == "timeSlider") {
QVariantMap params;
params["channel"] = curPlayChannel;
params["channel"] = curSelectChannel;
params["year"] = ui->cmbYear->currentText();
params["month"] = ui->cmbMonth->currentText();
params["day"] = ui->cmbDay->currentText();
QList<DatabaseManager::File> list = db->get(params);
// 搜索当前播放视频的位置
int index = -1;
for (int i = 0; i < list.length(); i++) {
DatabaseManager::File file = list[i];
if (file.filename == curPlayFilename) {
index = i;
break;
}
}
Log::info("find file filename: {}, index: {}", curPlayFilename.toStdString(), index);
// 查找目标文件名
QString filename;
if (type == "previous") {
// 已经是第一个视频了
if (index == 0) {
emit btnVideoClicked("first");
return;
}
index -= 1;
} else {
// 已经是最后一个视频
if (index == list.length() - 1) {
emit btnVideoClicked("last");
return;
}
index += 1;
}
filename = list[index].filename;
Log::info("type: {}, index: {}, filename",
type.toStdString(),
index,
filename.toStdString());
emit btnVideoClicked(filename);
curPlayFilename = filename;
// 单通道回放
if (channelSelectVisible) {
// 选中通道和回放通道不是同一个时不处理
if (curPlayChannel != curSelectChannel) {
return;
}
}
// 双通道同时回放
else {
if (curPlayChannel != DatabaseManager::MainChannel) {
return;
}
}
// 选中要播放的按钮
QList<QPushButton*> btns = ui->scrollArea->findChildren<QPushButton*>();
for (QPushButton* btn : btns) {
if (btn->property("name").toString() == filename) {
btn->setChecked(true);
btn->setFocus();
emit btnPlaybackClicked(params, curSegmentIndex);
hide();
}
// 确认按钮按下确认
else if (focusWidget->objectName() == "btn_done") {
renderTimeSlider();
}
}
@ -392,30 +268,6 @@ QList<QWidget*> Menu::getAllFocusabelWidget()
return result;
}
/**
* @brief
* @param channelName
*/
void Menu::onAppendOneVideo(QString channelName)
{
// 单通道
if (channelSelectVisible) {
// 只有生成新视频的通道和当前选择的通道一致时重新获取文件列表
if ((channelName == Constant::MainChannel
&& curSelectChannel == DatabaseManager::MainChannel)
|| (channelName == Constant::SecondaryChannel
&& curSelectChannel == DatabaseManager::SecondaryChannel)) {
renderContents();
}
}
// 双通道
else {
if (channelName == Constant::MainChannel) {
renderContents();
}
}
}
/**
* @brief
* @return
@ -424,3 +276,111 @@ 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());
}
}

37
Menu.h
View File

@ -1,9 +1,12 @@
#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 {
@ -16,43 +19,55 @@ class Menu : public QWidget, public FW::FocusWindow {
public:
Menu(QWidget* parent = nullptr);
~Menu();
void show();
void setChannelSelectVisible(bool visible);
DatabaseManager::Channel getCurPlayChannel();
void moveToCenter();
void show();
Menu* restartUI();
public slots:
void move(Direction direction);
void confirm();
void clickPreOrNext(QString type);
void onAppendOneVideo(QString channelName);
void onAppendVideo();
signals:
void btnHdmi1Checked();
void btnHdmi2Checked();
void btnVga1Checked();
void btnVga2Checked();
void btnVideoClicked(QString name);
void btnPlaybackClicked(QVariantMap params, int segmentIndex);
void resolutionOutAChanged(int);
void resolutionOutBChanged(int);
void resolutionInAChanged(int width, int height);
void resolutionInBChanged(int width, int height);
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;
QString curPlayFilename; // 当前正在回放的文件名
bool channelSelectVisible = false; // 是否显示通道选择,单通道回放显示、双通道不显示
DatabaseManager::Channel curSelectChannel; // 当前选择的通道
DatabaseManager::Channel curPlayChannel; // 当前回放的通道
QList<TimeSlider::TimeSegment> segments; // 视频时间片
int curSegmentIndex; // 当前时间片
private:
void getContents();
void renderContents();
void renderComboBoxYear();
void renderComboBoxMonth();
void renderComboBoxDay();
void renderTimeSlider();
};
#endif // WIDGET_H

612
Menu.ui
View File

@ -34,6 +34,87 @@ QWidget:focus{
QPushButton:checked {
background: rgba(94,92,230, 0.5);
}
QComboBox{
background:rgba(33,33,33,0.5);
font: 10pt &quot;微软雅黑&quot;;
padding: 1px 15px 1px 3px;
border:1px solid rgba(228,228,228,0.5);
border-radius:5px 5px 0px 0px;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border:none;
}
QComboBox QAbstractItemView{
background:rgba(255,255,255,0.5);
border:1px solid rgba(228,228,228,0.5);
border-radius:0px 0px 5px 5px;
font-size:14px;
outline: 0px;
}
QComboBox QAbstractItemView::item{
height:36px;
color:#666666;
padding-left:9px;
background-color:rgba(255,255,255,0.5);
}
QComboBox QAbstractItemView::item:hover{
background-color:rgba(64,156,225,0.5);
color:#ffffff;
}
QComboBox QAbstractItemView::item:selected{
background-color:rgba(64,156,225,0.5);
color:#ffffff;
}
QComboBox:on {
padding-top: 3px;
padding-left: 4px;
}
QComboBox::down-arrow:on {
top: 1px;
left: 1px;
}
QScrollBar:vertical{
width:3px;
background:transparent;
margin:0px,0px,0px,0px;
padding-top:0px;
padding-bottom:0px;
}
QScrollBar::handle:vertical
{
width:3px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20
}
QScrollBar::handle:vertical:hover{
width:3px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20;
}
QScrollBar::add-line:vertical
{
height:0px;width:4px;
subcontrol-position:bottom;
}
QScrollBar::sub-line:vertical
{
height:0px;width:4px;
subcontrol-position:top;
}
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical
{
background:rgba(232,234,239,0.5);
border-radius:4px;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
@ -217,7 +298,7 @@ QPushButton:checked {
<string notr="true"/>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="styleSheet">
@ -238,7 +319,7 @@ QFrame#line
color:rgba(51,51,51,0.5);
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>20</number>
</property>
@ -254,6 +335,12 @@ QFrame#line
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>通道1</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QWidget" name="widget_2" native="true">
<property name="minimumSize">
@ -264,7 +351,7 @@ QFrame#line
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,1">
<property name="spacing">
<number>20</number>
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
@ -280,6 +367,12 @@ QFrame#line
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
@ -293,7 +386,7 @@ QFrame#line
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>通道1</string>
<string>接口模式:</string>
</property>
</widget>
</item>
@ -359,6 +452,178 @@ QFrame#line
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>输入分辨率:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbResolutionInA">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<item>
<property name="text">
<string>1920x1080</string>
</property>
</item>
<item>
<property name="text">
<string>1600x1200</string>
</property>
</item>
<item>
<property name="text">
<string>1280x1024</string>
</property>
</item>
<item>
<property name="text">
<string>1280X720</string>
</property>
</item>
<item>
<property name="text">
<string>1024x768</string>
</property>
</item>
<item>
<property name="text">
<string>800x600</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_10">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>输出分辨率:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbResolutionA">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<item>
<property name="text">
<string>1920x1080</string>
</property>
</item>
<item>
<property name="text">
<string>1600x1200</string>
</property>
</item>
<item>
<property name="text">
<string>1280x1024</string>
</property>
</item>
<item>
<property name="text">
<string>1280X720</string>
</property>
</item>
<item>
<property name="text">
<string>1024x768</string>
</property>
</item>
<item>
<property name="text">
<string>800x600</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>通道2</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QWidget" name="widget_3" native="true">
<property name="minimumSize">
@ -369,7 +634,7 @@ QFrame#line
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,1">
<property name="spacing">
<number>20</number>
<number>10</number>
</property>
<property name="leftMargin">
<number>0</number>
@ -385,6 +650,12 @@ QFrame#line
</property>
<item>
<widget class="QLabel" name="label_8">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
@ -398,7 +669,7 @@ QFrame#line
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>通道2</string>
<string>接口模式:</string>
</property>
</widget>
</item>
@ -464,6 +735,156 @@ QFrame#line
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_12">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>输入分辨率:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbResolutionInB">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<item>
<property name="text">
<string>1920x1080</string>
</property>
</item>
<item>
<property name="text">
<string>1600x1200</string>
</property>
</item>
<item>
<property name="text">
<string>1280x1024</string>
</property>
</item>
<item>
<property name="text">
<string>1280X720</string>
</property>
</item>
<item>
<property name="text">
<string>1024x768</string>
</property>
</item>
<item>
<property name="text">
<string>800x600</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>输出分辨率:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbResolutionB">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<item>
<property name="text">
<string>1920x1080</string>
</property>
</item>
<item>
<property name="text">
<string>1600x1200</string>
</property>
</item>
<item>
<property name="text">
<string>1280x1024</string>
</property>
</item>
<item>
<property name="text">
<string>1280X720</string>
</property>
</item>
<item>
<property name="text">
<string>1024x768</string>
</property>
</item>
<item>
<property name="text">
<string>800x600</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@ -479,6 +900,9 @@ QFrame#line
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="styleSheet">
<string notr="true">QPushButton {
@ -495,86 +919,9 @@ QPushButton:checked {
}
QComboBox{
background:rgba(255,255,255,0.5);
font: 10pt &quot;微软雅黑&quot;;
padding: 1px 15px 1px 3px;
border:1px solid rgba(228,228,228,0.5);
border-radius:5px 5px 0px 0px;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border:none;
}
QComboBox QAbstractItemView{
background:rgba(255,255,255,0.5);
border:1px solid rgba(228,228,228,0.5);
border-radius:0px 0px 5px 5px;
font-size:14px;
outline: 0px;
}
QComboBox QAbstractItemView::item{
height:36px;
color:#666666;
padding-left:9px;
background-color:rgba(255,255,255,0.5);
}
QComboBox QAbstractItemView::item:hover{
background-color:rgba(64,156,225,0.5);
color:#ffffff;
}
QComboBox QAbstractItemView::item:selected{
background-color:rgba(64,156,225,0.5);
color:#ffffff;
}
QComboBox:on {
padding-top: 3px;
padding-left: 4px;
}
QComboBox::down-arrow:on {
top: 1px;
left: 1px;
}
QScrollBar:vertical{
width:3px;
background:transparent;
margin:0px,0px,0px,0px;
padding-top:0px;
padding-bottom:0px;
}
QScrollBar::handle:vertical
{
width:3px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20
}
QScrollBar::handle:vertical:hover{
width:3px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20;
}
QScrollBar::add-line:vertical
{
height:0px;width:4px;
subcontrol-position:bottom;
}
QScrollBar::sub-line:vertical
{
height:0px;width:4px;
subcontrol-position:top;
}
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical
{
background:rgba(232,234,239,0.5);
border-radius:4px;
}</string>
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6" stretch="0,0">
<layout class="QVBoxLayout" name="verticalLayout_6" stretch="0,0,0">
<property name="spacing">
<number>6</number>
</property>
@ -650,7 +997,7 @@ border-radius:4px;
</size>
</property>
<property name="text">
<string>通道1</string>
<string>通道</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -681,7 +1028,7 @@ border-radius:4px;
<string notr="true"/>
</property>
<property name="text">
<string>通道2</string>
<string>通道</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -828,73 +1175,36 @@ border-radius:4px;
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<widget class="TimeSlider" name="timeSlider" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>90</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
<enum>Qt::StrongFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">QScrollArea {
background-color:rgba(25, 25, 25, 0.5);
<string notr="true">QWidget:focus{
border: 3px solid rgba(15,216,82, 0.5);
}
QScrollBar:vertical{
width:8px;
background:transparent;
margin:0px,0px,0px,0px;
padding-top:0px;
padding-bottom:0px;
}
QScrollBar::handle:vertical
{
width:8px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20
}
QScrollBar::handle:vertical:hover{
width:8px;
background:rgba(69,178,255,70%);
border-radius:4px;
min-height:20;
}
QScrollBar::add-line:vertical
{
height:0px;width:8px;
subcontrol-position:bottom;
}
QScrollBar::sub-line:vertical
{
height:0px;width:8px;
subcontrol-position:top;
}
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical
{
background:rgba(232,234,239,0.5);
border-radius:4px;
}</string>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>776</width>
<height>416</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QWidget#scrollAreaWidgetContents {
background: rgba(25, 25, 25, 0.5);
border: none;
}
</string>
</property>
</widget>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
@ -904,6 +1214,14 @@ border-radius:4px;
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TimeSlider</class>
<extends>QWidget</extends>
<header location="global">TimeSlider.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -1,120 +0,0 @@
#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"));
}
}

View File

@ -1,50 +0,0 @@
#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"));
return formatStr;
}
#endif // PROGRESSBAR_H

View File

@ -1,144 +0,0 @@
<?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>

View File

@ -34,7 +34,6 @@ SOURCES += \
TcpServer.cpp \
Channel.cpp \
Menu.cpp\
ProgressBar.cpp \
Tool.cpp \
CheckStorageThread.cpp \
Constant.h \
@ -45,14 +44,14 @@ SOURCES += \
TcpResponse.cpp \
SerialPortTool.cpp \
FocusWindow.cpp \
DatabaseManager.cpp
DatabaseManager.cpp \
TimeSlider.cpp
HEADERS += \
Widget.h \
TcpServer.h \
Channel.h \
Menu.h \
ProgressBar.h \
Tool.h \
CheckStorageThread.h \
Log.h \
@ -62,11 +61,11 @@ HEADERS += \
TcpResponse.h \
SerialPortTool.h \
FocusWindow.h \
DatabaseManager.h
DatabaseManager.h \
TimeSlider.h
FORMS += \
Menu.ui \
ProgressBar.ui \
Widget.ui
RESOURCES += \

View File

@ -28,7 +28,6 @@ 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");
@ -47,10 +46,6 @@ 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()
@ -193,12 +188,6 @@ void SerialPortTool::onReayRead()
}
}
void SerialPortTool::onReset()
{
serialPort->write(cmdMap.value(Reset));
serialPort->flush();
}
void SerialPortTool::onPlaybackStart()
{
serialPort->write(cmdMap.value(PlaybackStart));
@ -307,30 +296,3 @@ 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();
}

View File

@ -14,29 +14,33 @@ 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);

213
TimeSlider.cpp Normal file
View File

@ -0,0 +1,213 @@
#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 Normal file
View File

@ -0,0 +1,71 @@
/******************************************************************************
* @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

View File

@ -1,5 +1,7 @@
#include "Tool.h"
#include "DatabaseManager.h"
#include "QTimer"
#include "TimeSlider.h"
#include <QDebug>
#include <QDir>
#include <QElapsedTimer>
@ -138,3 +140,38 @@ 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
View File

@ -1,5 +1,6 @@
#ifndef TOOL_H
#define TOOL_H
#include "TimeSlider.h"
#include <QString>
#include <functional>
@ -17,6 +18,8 @@ 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

View File

@ -7,11 +7,16 @@
#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;
@ -31,12 +36,16 @@ 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);
ui->progressBar->hide();
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)));
// 每5秒更新一次进度条
progressTimer = new QTimer();
@ -46,14 +55,17 @@ 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(QString)), menu, SLOT(onAppendOneVideo(QString)));
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);
@ -62,7 +74,10 @@ 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);
@ -84,28 +99,39 @@ Widget::Widget(QWidget* parent)
connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked()));
connect(serialPortTool, SIGNAL(btnVolumnUpClicked()), this, SLOT(onBtnVolumnUpClicked()));
connect(serialPortTool, SIGNAL(btnVolumnDownClicked()), this, SLOT(onBtnVolumnDownClicked()));
connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString)));
connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickPreOrNext(QString)));
}
Widget::~Widget()
{
delete ui;
delete progressTimer;
delete menu;
// delete menu;
}
/**
* @brief
* @brief
*/
void Widget::onProgressTimeout()
{
Channel* chn = findChannelByName(Constant::MainChannel);
// 获取当前回放的通道名称
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);
if (chn) {
// 获取当前播放位置单位ms
int pos = chn->inputFile->invoke("getPosition").toInt();
ui->progressBar->setCurrent(pos);
// 获取当前播放位置单位s
int pos = chn->inputFile->invoke("getPosition").toInt() / 1000;
int cur = segments[curSegmentIndex].startTime + pos;
ui->timeSlider->setCurrent(cur);
}
}
@ -116,6 +142,7 @@ void Widget::onBtnMenuClicked()
{
if (!menu->isVisible()) {
menu->show();
menu->moveToCenter();
}
}
@ -138,11 +165,9 @@ void Widget::onBtnReturnClicked()
serialPortTool->onPlaybackEnd();
}
}
// 隐藏进度条并关闭定时器
ui->progressBar->hide();
progressTimer->stop();
// 显示录制状态
// ui->recordWidget->show();
isPlayback = false;
ui->timeSlider->hide();
}
}
@ -155,8 +180,9 @@ void Widget::onBtnUpClicked()
menu->move(Menu::Up);
return;
}
// 时间轴选中移动到上一个视频的开始
if (isPlayback) {
emit needPlayVideo("previous");
playPreSegment();
}
}
@ -169,8 +195,9 @@ void Widget::onBtnDownClicked()
menu->move(Menu::Down);
return;
}
// 时间轴移动到下一个视频
if (isPlayback) {
emit needPlayVideo("next");
playNextSegemnt();
}
}
@ -217,13 +244,10 @@ 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();
}
@ -250,28 +274,100 @@ void Widget::onBtnVolumnDownClicked()
}
/**
* @brief
* @brief
* @param params ()
* @param segmentIndex
*/
void Widget::onBtnVideoClicked(QString filename)
void Widget::onBtnPlaybackClicked(QVariantMap params, int segmentIndex)
{
if (filename == "first") {
qDebug() << "click previous failed, already the first video";
// 显示提示弹窗
} else if (filename == "last") {
if (playbackMode == Constant::OneChannelPlayback) {
Channel* chn = findChannelByName(Constant::MainChannel);
chn->showFinishPromot();
} else {
for (Channel* chn : channelList)
chn->showFinishPromot();
if (segmentIndex < 0) {
return;
}
} else {
// 获取当前通道
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);
} else {
playTwoChannels(filename);
}
serialPortTool->onPlaybackStart();
}
/**
* @brief A分辨率修改
* @param resolution
*/
void Widget::onResolutionOutAChanged(int resolution)
{
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);
}
}
}
@ -292,9 +388,7 @@ void Widget::playOneChannel(QString filename)
bool ret = channel->startPlayback(path);
if (!ret) {
Log::info("play back error");
ui->progressBar->hide();
}
isPlayback = true;
// 全局保存当前播放的视频的文件名
mutex.lock();
@ -302,13 +396,6 @@ void Widget::playOneChannel(QString 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();
@ -328,12 +415,6 @@ 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();
@ -342,7 +423,6 @@ void Widget::playTwoChannels(QString filename)
}
ui->recordWidget->hide();
} else {
ui->progressBar->hide();
ui->recordWidget->hide();
}
}
@ -362,18 +442,86 @@ void Widget::seek(QString type)
{
if (!isPlayback)
return;
for (Channel* chn : channelList) {
if (chn->state == Channel::Pause || chn->state == Channel::Playback) {
if (type == "forward") {
chn->forward();
serialPortTool->onFoward();
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 {
chn->back();
serialPortTool->onBack();
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;
}
}
}
if (chn->channelName == Constant::MainChannel)
ui->progressBar->showMax();
} 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());
}
}
}
@ -396,7 +544,23 @@ void Widget::onPlayEnd()
}
}
}
emit needPlayVideo("next");
// 如果时列表最后一个视频则显示播放结束
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);
}
}
}
/**
@ -437,3 +601,82 @@ 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();
}

View File

@ -3,7 +3,7 @@
#include "Channel.h"
#include "Menu.h"
#include "ProgressBar.h"
#include "TimeSlider.h"
#include <QDir>
#include <QMap>
#include <QTimer>
@ -22,10 +22,13 @@ public:
signals:
void needPlayVideo(QString types);
private slots:
public slots:
void update();
void onProgressTimeout();
void onPlayEnd();
void onShowRecordLabel(bool show);
void onAppendVideo();
// 按键操作。上下左右确认返回
void onBtnMenuClicked();
@ -39,19 +42,32 @@ private slots:
void onBtnVolumnDownClicked();
// 播放视频
void onBtnVideoClicked(QString filename);
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);
private:
Ui::Widget* ui;
QTimer* progressTimer;
bool isPlayback = false;
Menu* menu;
Menu* menu; // 菜单指针
bool isPlayback = false; // 是否在回放
QTimer* progressTimer; // 查询播放进度的定时器
QList<TimeSlider::TimeSegment> segments; // 当天回放的时间段
int curSegmentIndex = 0; // 当前回放的时间段
QVariantMap playbackParams; // 回放参数(通道和时间)
private:
void seek(QString type);
void playOneChannel(QString filename);
void playTwoChannels(QString filename);
void playNextSegemnt();
void playPreSegment();
Channel* findChannelByName(QString name);
};

View File

@ -217,7 +217,7 @@
</spacer>
</item>
<item>
<widget class="ProgressBar" name="progressBar" native="true"/>
<widget class="TimeSlider" name="timeSlider" native="true"/>
</item>
</layout>
</item>
@ -226,9 +226,9 @@
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>ProgressBar</class>
<class>TimeSlider</class>
<extends>QWidget</extends>
<header location="global">ProgressBar.h</header>
<header location="global">TimeSlider.h</header>
<container>1</container>
</customwidget>
</customwidgets>

136
main.cpp
View File

@ -20,10 +20,7 @@ TcpServer* server;
SerialPortTool* serialPortTool;
// 数据库管理
DatabaseManager* db;
// 视频输出通道
LinkObject* vo;
LinkObject* vo1;
// 硬盘检测现场
// 硬盘检测线程
CheckStorageThread* thread;
// 通道列表
@ -32,8 +29,6 @@ QList<Channel*> channelList;
Constant::RecordMode recordMode;
// 回放模式
Constant::PlaybackMode playbackMode;
QString mainChannelProtocol;
QString secondaryChannelProtocol;
/**
* @brief
@ -52,14 +47,13 @@ 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();
chn->channelName = cfg["name"].toString();
if (chn->channelName == Constant::MainChannel) {
mainChannelProtocol = cfg["protocol"].toString();
} else if (chn->channelName == Constant::SecondaryChannel) {
secondaryChannelProtocol = cfg["protocol"].toString();
QString channelName = cfg["name"].toString();
if (channelName.isEmpty()) {
return false;
}
QVariantMap output = cfg["output"].toMap();
Channel* chn = new Channel(channelName, output);
QVariantMap encV = cfg["encV"].toMap();
chn->videoEncoderParams = encV;
@ -69,7 +63,6 @@ bool loadConfiguration(QString path)
chn->pushCode = cfg["pushCode"].toString();
chn->init();
channelList.push_back(chn);
}
return true;
@ -94,10 +87,8 @@ void startRecord()
for (Channel* chn : channelList) {
if (chn->channelName == Constant::MainChannel) {
chn->startRecord();
// QThread::msleep(100);
serialPortTool->onRecordStart();
QThread::msleep(100);
// serialPortTool->onLoopOff();
}
}
}
@ -107,50 +98,19 @@ 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"(
____ _ _____
/ ___|| |__ __ _ _ __ | ___|__ _ __ __ _
\___ \| '_ \ / _` | '_ \| |_ / _ \ '_ \ / _` |
___) | | | | (_| | | | | _| __/ | | | (_| |
|____/|_| |_|\__,_|_| |_|_| \___|_| |_|\__, |
|___/ )");
qDebug() << (R"(
____ _ _ _ __ __ _
/ ___|| |_ __ _ _ __| |_ ___ __| | \ \ / /__| | ___ ___ _ __ ___ ___
\___ \| __/ _` | '__| __/ _ \/ _` | \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
___) | || (_| | | | || __/ (_| | \ V V / __/ | (_| (_) | | | | | | __/
|____/ \__\__,_|_| \__\___|\__,_| \_/\_/ \___|_|\___\___/|_| |_| |_|\___|
)");
// qDebug() << (R"(
// ____ _ _____
// / ___|| |__ __ _ _ __ | ___|__ _ __ __ _
// \___ \| '_ \ / _` | '_ \| |_ / _ \ '_ \ / _` |
// ___) | | | | (_| | | | | _| __/ | | | (_| |
// |____/|_| |_|\__,_|_| |_|_| \___|_| |_|\__, |
// |___/ )");
// std::atexit(resetLight);
// 初始化日志
Log::init();
@ -160,74 +120,26 @@ 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;
@ -236,8 +148,8 @@ int main(int argc, char* argv[])
// 硬盘检测线程,检测硬盘容量
thread = new CheckStorageThread();
thread->start();
QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull()));
QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull()));
QObject::connect(thread, SIGNAL(diskWillFull()), serialPortTool, SLOT(onDiskWillFull()), Qt::QueuedConnection);
QObject::connect(thread, SIGNAL(diskNotFull()), serialPortTool, SLOT(onDiskNotFull()), Qt::QueuedConnection);
Log::info("start storage check thread...");
// 开始录制