RecordControlApplication/Widget.cpp

558 lines
15 KiB
C++
Raw 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"
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 <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>
// 多线程中使用
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;
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-03-04 16:22:40 +08:00
ui->lblA->setPixmap(QPixmap(":/images/no-record.png"));
ui->lblB->setPixmap(QPixmap(":/images/no-record.png"));
2024-01-18 15:41:43 +08:00
menu = new Menu(this);
menu->hide();
progressBar = new ProgressBar(this);
progressBar->hide();
2024-03-04 16:22:40 +08:00
message = new Message(this);
// 设置窗体背景透明
2024-01-18 15:41:43 +08:00
QPalette pal = palette();
pal.setBrush(QPalette::Base, Qt::transparent);
setPalette(pal);
setAttribute(Qt::WA_TranslucentBackground, true);
2024-03-04 16:22:40 +08:00
// 设置listwidget无滚动条
2024-01-18 15:41:43 +08:00
ui->listWidget->horizontalScrollBar()->hide();
ui->listWidget->verticalScrollBar()->hide();
ui->listWidget->hide();
2024-03-04 16:22:40 +08:00
// 初始化串口
2024-01-18 15:41:43 +08:00
initSerialPort();
2024-03-04 16:22:40 +08:00
// 初始化指令列表
2024-01-18 15:41:43 +08:00
initCommandMap();
2024-03-04 16:22:40 +08:00
// 每5秒更新一次进度条
progressTimer = new QTimer();
progressTimer->setInterval(500);
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)));
}
2024-01-18 15:41:43 +08:00
}
Widget::~Widget()
{
serialPort->close();
delete ui;
2024-03-04 16:22:40 +08:00
delete timer;
delete progressTimer;
delete menu;
delete progressBar;
delete message;
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Widget::initSerialPort()
{
2024-03-04 16:22:40 +08:00
// 用于重连串口的timer
2024-01-18 15:41:43 +08:00
timer = new QTimer();
timer->setInterval(3000);
2024-01-18 15:41:43 +08:00
timer->stop();
serialPort = new QSerialPort();
serialPort->setPortName("ttyAMA2");
serialPort->setBaudRate(QSerialPort::Baud115200);
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
if (serialPort->open(QIODevice::ReadWrite)) {
2024-03-04 16:22:40 +08:00
Log::info("open serial port: /dev/ttyAMA2 success");
2024-01-18 15:41:43 +08:00
} else {
2024-03-04 16:22:40 +08:00
Log::error("open serial port: /dev/ttyAMA2 failed, ready to retry...");
2024-01-18 15:41:43 +08:00
timer->start();
}
connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onSerialError(QSerialPort::SerialPortError)));
connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Widget::showPlayList()
{
2024-03-04 16:22:40 +08:00
QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curSelectChannel);
QStringList files = Tool::getFileList(dirPath);
2024-01-18 15:41:43 +08:00
ui->listWidget->clear();
for (QString& file : files) {
2024-01-18 15:41:43 +08:00
QListWidgetItem* item = new QListWidgetItem(file);
ui->listWidget->addItem(item);
}
ui->listWidget->show();
ui->listWidget->setCurrentRow(0);
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Widget::onTimeout()
{
timer->stop();
bool ret = serialPort->open(QIODevice::ReadWrite);
if (!ret) {
2024-03-04 16:22:40 +08:00
Log::info("reopen serial port: /dev/ttyAMA2 success");
2024-01-18 15:41:43 +08:00
timer->start();
} else {
2024-03-04 16:22:40 +08:00
Log::error("reopen serial port: /dev/ttyAMA2 failed, ready to retry...");
2024-01-18 15:41:43 +08:00
}
}
2024-03-04 16:22:40 +08:00
/**
* @brief
*/
void Widget::onProgressTimeout()
{
2024-03-04 16:22:40 +08:00
Channel* chn = findChannelByName(Constant::MainChannel);
int pos = chn->file->invoke("getPosition").toInt() / 1000;
progressBar->setCurrent(pos);
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
* @param error
*/
void Widget::onSerialError(QSerialPort::SerialPortError error)
{
if (error == QSerialPort::ResourceError) {
2024-03-04 16:22:40 +08:00
Log::error("serial port break, try to reopen");
2024-01-18 15:41:43 +08:00
serialPort->close();
timer->start();
}
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Widget::initCommandMap()
{
2024-03-04 16:22:40 +08:00
commandMap.insert("A1", CmdPlayback);
commandMap.insert("A2", CmdNext);
commandMap.insert("A3", CmdPrevious);
commandMap.insert("A4", CmdForward);
commandMap.insert("A5", CmdBack);
commandMap.insert("A6", CmdPause);
commandMap.insert("A7", CmdReturn);
commandMap.insert("A8", CmdEnter);
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
2024-01-18 15:41:43 +08:00
*/
void Widget::onReadyRead()
{
serialPort->waitForReadyRead(100);
QString data = serialPort->readLine();
if (!commandMap.contains(data)) {
2024-03-04 16:22:40 +08:00
Log::error("receive unkown command {} from serial port: /dev/ttyAMA2", data.toStdString());
2024-01-18 15:41:43 +08:00
return;
}
Command cmd = commandMap.value(data);
switch (cmd) {
2024-03-04 16:22:40 +08:00
case CmdPlayback:
receivePlayback();
break;
case CmdPrevious:
receivePrevious();
break;
case CmdNext:
receiveNext();
break;
case CmdForward:
seek("forward");
break;
case CmdBack:
seek("next");
break;
case CmdPause:
receivePasue();
break;
case CmdEnter:
receiveEnter();
break;
case CmdReturn:
receiveReturn();
break;
default:
break;
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
}
/**
* @brief
*/
void Widget::receivePlayback()
{
Log::info("receive command playback, playback mode: {}", playbackMode);
// 如果是一路回放,显示选择菜单
if (playbackMode == Constant::OneChannelPlayback) {
if (!menu->isVisible())
menu->show();
}
// 两路回放不显示菜单,直接显示列表
else if (playbackMode == Constant::TwoChannelPlayback) {
curSelectChannel = Constant::MainChannel;
showPlayList();
}
}
/**
* @brief
*/
void Widget::receivePrevious()
{
// 菜单显示则切换菜单选中
if (menu->isVisible()) {
menu->setCurChannel(Constant::MainChannel);
return;
}
// 列表显示,则选中上一个视频
if (ui->listWidget->isVisible()) {
int curRow = ui->listWidget->currentRow();
if (curRow == 0)
curRow = ui->listWidget->count();
ui->listWidget->setCurrentRow(curRow - 1);
return;
}
if (isPlayback) {
}
}
/**
* @brief
*/
void Widget::receiveNext()
{
if (menu->isVisible()) {
menu->setCurChannel(Constant::SecondaryChannel);
return;
}
if (ui->listWidget->isVisible()) {
int curRow = ui->listWidget->currentRow();
if (curRow == ui->listWidget->count() - 1) {
curRow = -1;
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
ui->listWidget->setCurrentRow(curRow + 1);
return;
}
if (isPlayback) {
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
}
/**
* @brief
*/
void Widget::receivePasue()
{
if (!isPlayback)
return;
for (Channel* chn : channelList) {
if (chn->state == Channel::Playback || chn->state == Channel::Pause) {
chn->togglePause();
if (chn->channelName == Constant::MainChannel) {
progressBar->showMax();
if (chn->state == Channel::Pause) {
progressBar->setState(ProgressBar::Pause);
} else {
progressBar->setState(ProgressBar::Play);
}
2024-01-18 15:41:43 +08:00
}
}
}
2024-03-04 16:22:40 +08:00
}
/**
* @brief
*/
void Widget::receiveEnter()
{
// 菜单显示,则关闭菜单显示列表
if (menu->isVisible()) {
curSelectChannel = menu->getCurChannel();
menu->hide();
showPlayList();
return;
}
if (ui->listWidget->isVisible()) {
if (ui->listWidget->count() == 0)
return;
if (playbackMode == Constant::OneChannelPlayback)
playOneChannel();
else if (playbackMode == Constant::TwoChannelPlayback)
playTwoChannels();
return;
}
}
/**
* @brief
* : ==> ==>
*/
void Widget::receiveReturn()
{
if (menu->isVisible()) {
menu->hide();
return;
}
if (ui->listWidget->isVisible()) {
ui->listWidget->hide();
return;
}
if (isPlayback) {
// 停止回放
for (Channel* chn : channelList) {
if (chn->state != Channel::Stop)
chn->startPlayLive();
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
progressBar->hide();
ui->lblA->show();
ui->lblB->show();
}
}
/**
* @brief
*/
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();
else
chn->back();
if (chn->channelName == Constant::MainChannel)
progressBar->showMax();
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
}
}
/**
* @brief HDMI-OUT0口输出
*/
void Widget::playOneChannel()
{
QString filename = ui->listWidget->currentItem()->text();
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curSelectChannel).arg(filename);
Channel* channel = findChannelByName(Constant::MainChannel);
for (Channel* chn : channelList) {
chn->startPlayLive();
}
bool ret = channel->startPlayback(path);
if (!ret)
progressBar->hide();
isPlayback = true;
curPlayChannel = curSelectChannel;
curPlayFilename = filename;
// 全局保存当前播放的视频
mutex.lock();
curFilename = filename;
condition.wakeAll();
mutex.unlock();
// 保存当前播放视频列表
QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curPlayChannel);
fileList = Tool::getFileList(dirPath);
int duration = channel->playbackDuration;
progressBar->setDuration(duration);
progressBar->setCurrent(0);
progressBar->show();
progressBar->showMax();
progressBar->setState(ProgressBar::Play);
if (progressTimer->isActive()) {
progressTimer->stop();
progressTimer->start();
} else {
progressTimer->start();
}
ui->lblA->hide();
ui->lblB->hide();
}
/**
* @brief HDMI-A口的视频为主分别从HDMI-OUT0和HDMI-OUT1输出
*/
void Widget::playTwoChannels()
{
QString filename = ui->listWidget->currentItem()->text();
for (Channel* chn : channelList) {
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(filename);
int ret = chn->startPlayback(path);
if (chn->channelName == Constant::MainChannel) {
if (ret) {
int duration = chn->playbackDuration;
progressBar->setDuration(duration);
progressBar->setCurrent(0);
progressBar->show();
progressBar->showMax();
progressBar->setState(ProgressBar::Play);
2024-03-04 16:22:40 +08:00
if (progressTimer->isActive()) {
progressTimer->stop();
progressTimer->start();
} else {
progressTimer->start();
2024-01-18 15:41:43 +08:00
}
2024-03-04 16:22:40 +08:00
ui->lblA->hide();
ui->lblB->hide();
} else {
progressBar->hide();
2024-01-18 15:41:43 +08:00
}
}
}
2024-03-04 16:22:40 +08:00
curPlayFilename = filename;
curPlayChannel = Constant::MainChannel;
isPlayback = true;
// 全局保存正在播放的视频
mutex.lock();
curFilename = filename;
condition.wakeAll();
mutex.unlock();
// 将HDMI-A通道的视频列表作为主列表
QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(Constant::MainChannel);
fileList = Tool::getFileList(dirPath);
2024-01-18 15:41:43 +08:00
}
/**
2024-03-04 16:22:40 +08:00
* @brief
*/
void Widget::onPlayEnd()
{
2024-03-04 16:22:40 +08:00
// 当两路回放时,只处理一次槽函数
if (playbackMode == Constant::TwoChannelPlayback) {
LinkObject* file = static_cast<LinkObject*>(sender());
for (Channel* chn : channelList) {
if (chn->file == file) {
if (chn->channelName != Constant::MainChannel) {
return;
}
}
}
}
// 计算下一个文件名
int index = fileList.indexOf(curPlayFilename);
if (index == fileList.length() - 1) {
2024-03-04 16:22:40 +08:00
QString dirPath = QString("%1/%2").arg(Constant::VideoPath).arg(curPlayChannel);
fileList = Tool::getFileList(dirPath);
if (index == fileList.length() - 1) {
2024-03-04 16:22:40 +08:00
Log::info("no file to play");
return;
}
2024-03-04 16:22:40 +08:00
Log::info("refresh current play file list");
}
curPlayFilename = fileList.at(index + 1);
// 播放下一个视频
if (playbackMode == Constant::OneChannelPlayback) {
Channel* chn = findChannelByName(Constant::MainChannel);
if (chn) {
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curPlayChannel).arg(curPlayFilename);
bool ret = chn->startPlayback(path);
if (chn->channelName == Constant::MainChannel) {
if (!ret) {
progressBar->hide();
return;
}
int duration = chn->playbackDuration;
progressBar->setDuration(duration);
progressBar->showMax();
}
}
} else if (playbackMode == Constant::TwoChannelPlayback) {
for (Channel* chn : channelList) {
QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(curPlayFilename);
bool ret = chn->startPlayback(path);
if (chn->channelName == Constant::MainChannel) {
if (!ret) {
progressBar->hide();
continue;
}
int duration = chn->playbackDuration;
progressBar->setDuration(duration);
progressBar->showMax();
}
}
}
2024-03-04 16:22:40 +08:00
mutex.lock();
curFilename = curPlayFilename;
condition.wakeAll();
mutex.unlock();
}
/**
* @brief
* @param show
*/
void Widget::onShowRecordLabel(bool show)
{
Channel* chn = static_cast<Channel*>(sender());
QLabel* label;
if (chn->channelName == Constant::MainChannel) {
label = ui->lblA;
} else {
label = ui->lblB;
}
if (show) {
label->setPixmap(QPixmap(":/images/record.png"));
} else
label->setPixmap(QPixmap(":/images/no-record.png"));
}
/**
* @brief
* @param name
*/
Channel* Widget::findChannelByName(QString name)
{
for (Channel* chn : channelList) {
if (chn->channelName == name) {
return chn;
}
}
return nullptr;
}