RecordControlApplication/Widget.cpp

683 lines
20 KiB
C++
Raw Permalink Normal View History

2024-01-18 15:41:43 +08:00
#include "Widget.h"
#include "Channel.h"
2024-03-04 16:22:40 +08:00
#include "Constant.h"
#include "Json.h"
#include "Log.h"
#include "SerialPortTool.h"
2024-01-18 15:41:43 +08:00
#include "TcpServer.h"
2024-03-04 16:22:40 +08:00
#include "Tool.h"
2024-01-18 15:41:43 +08:00
#include "ui_Widget.h"
#include <QApplication>
#include <QDesktopWidget>
2024-01-18 15:41:43 +08:00
#include <QDir>
2024-03-04 16:22:40 +08:00
#include <QMutex>
2024-01-18 15:41:43 +08:00
#include <QScrollBar>
2024-03-04 16:22:40 +08:00
#include <QWaitCondition>
// 认为两个视频是连续的时间间隔阈值
#define TIME_GAP_THRRSHOLD 2
2024-03-04 16:22:40 +08:00
// 多线程中使用
QMutex mutex;
QWaitCondition condition;
QString curFilename;
2024-01-18 15:41:43 +08:00
extern QList<Channel*> channelList;
2024-03-04 16:22:40 +08:00
extern Constant::PlaybackMode playbackMode;
extern SerialPortTool* serialPortTool;
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
Widget::Widget(QWidget* parent)
2024-01-18 15:41:43 +08:00
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
2024-08-12 11:26:42 +08:00
ui->lblImgA->setPixmap(QPixmap(":/images/no-record.png"));
ui->lblImgB->setPixmap(QPixmap(":/images/no-record.png"));
ui->lblTxtA->setText("未录制");
ui->lblTxtB->setText("未录制");
ui->recordWidget->hide();
ui->timeSlider->hide();
ui->timeSlider->setOpacity(0.5);
2024-01-18 15:41:43 +08:00
2024-08-12 11:26:42 +08:00
menu = new Menu();
2024-01-18 15:41:43 +08:00
menu->hide();
2024-08-12 11:26:42 +08:00
// 设置是否显示通道选择
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)));
2024-01-18 15:41:43 +08:00
2024-03-04 16:22:40 +08:00
// 每5秒更新一次进度条
progressTimer = new QTimer();
2024-08-12 11:26:42 +08:00
progressTimer->setInterval(200);
connect(progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimeout()));
for (Channel* chn : channelList) {
connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd()));
2024-03-04 16:22:40 +08:00
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);
if (chn->channelName == Constant::MainChannel) {
serialPortTool->onMainChannelOn();
QThread::msleep(100);
} else {
serialPortTool->onSecondaryChannelOn();
QThread::msleep(100);
}
} else {
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);
} else {
serialPortTool->onSecondaryChannelOff();
QThread::msleep(100);
}
}
}
});
}
2024-08-12 11:26:42 +08:00
connect(serialPortTool, SIGNAL(btnMenuClicked()), this, SLOT(onBtnMenuClicked()));
connect(serialPortTool, SIGNAL(btnUpClicked()), this, SLOT(onBtnUpClicked()));
connect(serialPortTool, SIGNAL(btnDownClicked()), this, SLOT(onBtnDownClicked()));
connect(serialPortTool, SIGNAL(btnLeftClicked()), this, SLOT(onBtnLeftClicked()));
connect(serialPortTool, SIGNAL(btnRightClicked()), this, SLOT(onBtnRightClicked()));
connect(serialPortTool, SIGNAL(btnConfirmClicked()), this, SLOT(onBtnConfirmClicked()));
connect(serialPortTool, SIGNAL(btnReturnClicked()), this, SLOT(onBtnReturnClicked()));
connect(serialPortTool, SIGNAL(btnVolumnUpClicked()), this, SLOT(onBtnVolumnUpClicked()));
connect(serialPortTool, SIGNAL(btnVolumnDownClicked()), this, SLOT(onBtnVolumnDownClicked()));
2024-01-18 15:41:43 +08:00
}
Widget::~Widget()
{
delete ui;
2024-03-04 16:22:40 +08:00
delete progressTimer;
// delete menu;
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
/**
* @brief
2024-03-04 16:22:40 +08:00
*/
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);
2024-08-12 11:26:42 +08:00
if (chn) {
// 获取当前播放位置单位s
int pos = chn->inputFile->invoke("getPosition").toInt() / 1000;
int cur = segments[curSegmentIndex].startTime + pos;
ui->timeSlider->setCurrent(cur);
2024-08-12 11:26:42 +08:00
}
}
2024-03-04 16:22:40 +08:00
/**
2024-08-12 11:26:42 +08:00
* @brief
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnMenuClicked()
2024-03-04 16:22:40 +08:00
{
2024-08-12 11:26:42 +08:00
if (!menu->isVisible()) {
menu->show();
menu->moveToCenter();
2024-03-04 16:22:40 +08:00
}
}
/**
2024-08-12 11:26:42 +08:00
* @brief >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnReturnClicked()
2024-03-04 16:22:40 +08:00
{
2024-08-12 11:26:42 +08:00
// 关闭菜单
2024-03-04 16:22:40 +08:00
if (menu->isVisible()) {
2024-08-12 11:26:42 +08:00
menu->hide();
2024-03-04 16:22:40 +08:00
return;
}
2024-08-12 11:26:42 +08:00
// 关闭回放
if (isPlayback) {
// 停止回放
for (Channel* chn : channelList) {
if (chn->state != Channel::Stop) {
chn->startPlayLive();
serialPortTool->onPlaybackEnd();
}
}
progressTimer->stop();
isPlayback = false;
ui->timeSlider->hide();
2024-03-04 16:22:40 +08:00
}
}
/**
2024-08-12 11:26:42 +08:00
* @brief : >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnUpClicked()
2024-03-04 16:22:40 +08:00
{
if (menu->isVisible()) {
2024-08-12 11:26:42 +08:00
menu->move(Menu::Up);
2024-03-04 16:22:40 +08:00
return;
}
// 时间轴选中移动到上一个视频的开始
2024-08-12 11:26:42 +08:00
if (isPlayback) {
playPreSegment();
2024-03-04 16:22:40 +08:00
}
}
/**
2024-08-12 11:26:42 +08:00
* @brief : >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnDownClicked()
2024-03-04 16:22:40 +08:00
{
2024-08-12 11:26:42 +08:00
if (menu->isVisible()) {
menu->move(Menu::Down);
2024-03-04 16:22:40 +08:00
return;
2024-08-12 11:26:42 +08:00
}
// 时间轴移动到下一个视频
2024-08-12 11:26:42 +08:00
if (isPlayback) {
playNextSegemnt();
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
}
/**
2024-08-12 11:26:42 +08:00
* @brief : >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnLeftClicked()
2024-03-04 16:22:40 +08:00
{
if (menu->isVisible()) {
2024-08-12 11:26:42 +08:00
menu->move(Menu::Left);
2024-03-04 16:22:40 +08:00
return;
}
2024-08-12 11:26:42 +08:00
if (isPlayback) {
seek("back");
2024-03-04 16:22:40 +08:00
}
}
/**
2024-08-12 11:26:42 +08:00
* @brief : >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnRightClicked()
2024-03-04 16:22:40 +08:00
{
if (menu->isVisible()) {
2024-08-12 11:26:42 +08:00
menu->move(Menu::Right);
2024-03-04 16:22:40 +08:00
return;
}
if (isPlayback) {
2024-08-12 11:26:42 +08:00
seek("forward");
2024-03-04 16:22:40 +08:00
}
}
/**
2024-08-12 11:26:42 +08:00
* @brief ok键: >
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::onBtnConfirmClicked()
2024-03-04 16:22:40 +08:00
{
2024-08-12 11:26:42 +08:00
if (menu->isVisible()) {
menu->confirm();
2024-03-04 16:22:40 +08:00
return;
2024-08-12 11:26:42 +08:00
}
if (isPlayback) {
// 切换暂停和播放
for (Channel* chn : channelList) {
if (chn->state == Channel::Playback || chn->state == Channel::Pause) {
chn->togglePause();
if (chn->channelName == Constant::MainChannel) {
if (chn->state == Channel::Pause) {
// 打开暂停灯
serialPortTool->onPlayPause();
} else {
// 关闭暂停灯
serialPortTool->onPlayResume();
}
}
}
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
}
}
/**
* @brief
*/
void Widget::onBtnVolumnUpClicked()
{
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);
2024-08-12 11:26:42 +08:00
} else {
playTwoChannels(filename);
}
}
/**
* @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);
2024-08-12 11:26:42 +08:00
}
}
}
2024-03-04 16:22:40 +08:00
/**
* @brief HDMI-OUT0口输出
*/
2024-08-12 11:26:42 +08:00
void Widget::playOneChannel(QString filename)
2024-03-04 16:22:40 +08:00
{
// 获取当前回放的通道
QString curPlayChannel = menu->getCurPlayChannel() == DatabaseManager::MainChannel
? Constant::MainChannel
: Constant::SecondaryChannel;
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curPlayChannel).arg(filename);
2024-03-04 16:22:40 +08:00
Channel* channel = findChannelByName(Constant::MainChannel);
for (Channel* chn : channelList) {
chn->startPlayLive();
}
bool ret = channel->startPlayback(path);
2024-08-12 11:26:42 +08:00
if (!ret) {
Log::info("play back error");
}
2024-03-04 16:22:40 +08:00
isPlayback = true;
// 全局保存当前播放的视频的文件名
2024-03-04 16:22:40 +08:00
mutex.lock();
curFilename = filename;
condition.wakeAll();
mutex.unlock();
if (progressTimer->isActive()) {
progressTimer->stop();
progressTimer->start();
} else {
progressTimer->start();
}
2024-08-12 11:26:42 +08:00
ui->recordWidget->hide();
2024-03-04 16:22:40 +08:00
}
/**
* @brief HDMI-OUT0和HDMI-OUT1输出
2024-03-04 16:22:40 +08:00
*/
2024-08-12 11:26:42 +08:00
void Widget::playTwoChannels(QString filename)
2024-03-04 16:22:40 +08:00
{
for (Channel* chn : channelList) {
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(filename);
int ret = chn->startPlayback(path);
if (chn->channelName == Constant::MainChannel) {
if (ret) {
if (progressTimer->isActive()) {
progressTimer->stop();
progressTimer->start();
} else {
progressTimer->start();
2024-01-18 15:41:43 +08:00
}
2024-08-12 11:26:42 +08:00
ui->recordWidget->hide();
2024-03-04 16:22:40 +08:00
} else {
2024-08-12 11:26:42 +08:00
ui->recordWidget->hide();
2024-01-18 15:41:43 +08:00
}
}
}
2024-03-04 16:22:40 +08:00
isPlayback = true;
// 全局保存正在播放的视频的文件名
2024-03-04 16:22:40 +08:00
mutex.lock();
curFilename = filename;
condition.wakeAll();
mutex.unlock();
2024-08-12 11:26:42 +08:00
}
/**
* @brief
*/
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;
}
2024-08-12 11:26:42 +08:00
}
}
2024-03-04 16:22:40 +08:00
} 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());
2024-08-12 11:26:42 +08:00
}
}
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
*/
void Widget::onPlayEnd()
{
// 停下回放计时器
progressTimer->stop();
2024-03-04 16:22:40 +08:00
// 当两路回放时,只处理一次槽函数
if (playbackMode == Constant::TwoChannelPlayback) {
LinkObject* file = static_cast<LinkObject*>(sender());
for (Channel* chn : channelList) {
2024-08-12 11:26:42 +08:00
if (chn->inputFile == file) {
2024-03-04 16:22:40 +08:00
if (chn->channelName != Constant::MainChannel) {
return;
}
}
}
}
// 如果时列表最后一个视频则显示播放结束
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);
}
}
2024-03-04 16:22:40 +08:00
}
/**
* @brief
* @param show
*/
void Widget::onShowRecordLabel(bool show)
{
Channel* chn = static_cast<Channel*>(sender());
2024-08-12 11:26:42 +08:00
QLabel* lblImg;
QLabel* lblTxt;
2024-03-04 16:22:40 +08:00
if (chn->channelName == Constant::MainChannel) {
2024-08-12 11:26:42 +08:00
lblImg = ui->lblImgA;
lblTxt = ui->lblTxtA;
2024-03-04 16:22:40 +08:00
} else {
2024-08-12 11:26:42 +08:00
lblImg = ui->lblImgB;
lblTxt = ui->lblTxtB;
2024-03-04 16:22:40 +08:00
}
if (show) {
2024-08-12 11:26:42 +08:00
lblImg->setPixmap(QPixmap(":/images/record.png"));
lblTxt->setText("录制中");
} else {
lblImg->setPixmap(QPixmap(":/images/no-record.png"));
lblTxt->setText("未录制");
}
2024-03-04 16:22:40 +08:00
}
/**
* @brief
* @param name
*/
Channel* Widget::findChannelByName(QString name)
{
for (Channel* chn : channelList) {
if (chn->channelName == name) {
return chn;
}
}
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();
}