#include "Widget.h" #include "Channel.h" #include "Constant.h" #include "Json.h" #include "Log.h" #include "SerialPortTool.h" #include "TcpServer.h" #include "Tool.h" #include "ui_Widget.h" #include #include #include #include // 多线程中使用 QMutex mutex; QWaitCondition condition; QString curFilename; extern QList channelList; extern Constant::PlaybackMode playbackMode; extern SerialPortTool* serialPortTool; Widget::Widget(QWidget* parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); ui->lblImgA->setPixmap(QPixmap(":/images/no-record.png")); ui->lblImgB->setPixmap(QPixmap(":/images/no-record.png")); ui->lblTxtA->setText("未录制"); ui->lblTxtB->setText("未录制"); ui->recordWidget->hide(); menu = new Menu(); menu->hide(); // 设置是否显示通道选择 menu->setChannelSelectVisible(playbackMode == Constant::OneChannelPlayback); ui->progressBar->hide(); // 每5秒更新一次进度条 progressTimer = new QTimer(); progressTimer->setInterval(200); connect(progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimeout())); for (Channel* chn : channelList) { connect(chn, SIGNAL(playEnd()), this, SLOT(onPlayEnd())); connect(chn, SIGNAL(showRecordState(bool)), this, SLOT(onShowRecordLabel(bool))); // 监听输入信号的变化 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); } } } }); } 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(menu, SIGNAL(curChannelChanged(QString)), this, SLOT(onCurChannelChanged(QString))); connect(menu, SIGNAL(btnVideoClicked(QString)), this, SLOT(onBtnVideoClicked(QString))); connect(this, SIGNAL(needPlayVideo(QString)), menu, SLOT(clickVideo(QString))); } Widget::~Widget() { delete ui; delete progressTimer; delete menu; } /** * @brief 更新进度条 */ void Widget::onProgressTimeout() { Channel* chn = findChannelByName(Constant::MainChannel); if (chn) { // 获取当前播放位置,单位ms int pos = chn->inputFile->invoke("getPosition").toInt(); ui->progressBar->setCurrent(pos); } } /** * @brief 按下菜单按键 */ void Widget::onBtnMenuClicked() { if (!menu->isVisible()) { menu->show(); } } /** * @brief 按下返回按键。优先级:菜单 > 播放 */ void Widget::onBtnReturnClicked() { // 关闭菜单 if (menu->isVisible()) { menu->hide(); return; } // 关闭回放 if (isPlayback) { // 停止回放 for (Channel* chn : channelList) { if (chn->state != Channel::Stop) { chn->startPlayLive(); serialPortTool->onPlaybackEnd(); curPlayFilename = ""; } } // 隐藏进度条并关闭定时器 ui->progressBar->hide(); progressTimer->stop(); // 显示录制状态 // ui->recordWidget->show(); } } /** * @brief 按下上键。优先级: 菜单 > 播放 */ void Widget::onBtnUpClicked() { if (menu->isVisible()) { menu->move(Menu::Up); return; } if (isPlayback) { emit needPlayVideo("previous"); } } /** * @brief 按下下键。 优先级: 菜单 > 播放 */ void Widget::onBtnDownClicked() { if (menu->isVisible()) { menu->move(Menu::Down); return; } if (isPlayback) { emit needPlayVideo("next"); } } /** * @brief 按下左键。优先级: 菜单 > 播放。 */ void Widget::onBtnLeftClicked() { if (menu->isVisible()) { menu->move(Menu::Left); return; } if (isPlayback) { seek("back"); } } /** * @brief 按下左键。优先级: 菜单 > 播放 */ void Widget::onBtnRightClicked() { if (menu->isVisible()) { menu->move(Menu::Right); return; } if (isPlayback) { seek("forward"); } } /** * @brief 按下ok键。优先级: 菜单 > 回放 */ void Widget::onBtnConfirmClicked() { if (menu->isVisible()) { menu->confirm(); return; } if (isPlayback) { // 切换暂停和播放 for (Channel* chn : channelList) { if (chn->state == Channel::Playback || chn->state == Channel::Pause) { chn->togglePause(); if (chn->channelName == Constant::MainChannel) { ui->progressBar->showMax(); if (chn->state == Channel::Pause) { ui->progressBar->setState(ProgressBar::Pause); // 打开暂停灯 serialPortTool->onPlayPause(); } else { ui->progressBar->setState(ProgressBar::Play); // 关闭暂停灯 serialPortTool->onPlayResume(); } } } } } } /** * @brief 回放视频 */ void Widget::onBtnVideoClicked(QString filename) { if (filename == "first") { // 显示提示弹窗 } else if (filename == "last") { if (playbackMode == Constant::OneChannelPlayback) { Channel* chn = findChannelByName(Constant::MainChannel); chn->showFinishPromot(); } else { for (Channel* chn : channelList) chn->showFinishPromot(); } } else { if (playbackMode == Constant::OneChannelPlayback) { playOneChannel(filename); } else { playTwoChannels(filename); } serialPortTool->onPlaybackStart(); } } void Widget::onCurChannelChanged(QString channel) { curSelectChannel = channel; Log::info("channel switch, current channel:", channel.toStdString()); } /** * @brief 一路回放,将当前选中播放的视频从HDMI-OUT0口输出 */ void Widget::playOneChannel(QString filename) { QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(curSelectChannel).arg(filename); Channel* channel = findChannelByName(Constant::MainChannel); for (Channel* chn : channelList) { chn->startPlayLive(); } bool ret = channel->startPlayback(path); if (!ret) { Log::info("play back error"); ui->progressBar->hide(); } isPlayback = true; curPlayChannel = curSelectChannel; curPlayFilename = filename; // 全局保存当前播放的视频 mutex.lock(); curFilename = filename; condition.wakeAll(); mutex.unlock(); int duration = channel->playbackDuration; ui->progressBar->setDuration(duration); ui->progressBar->setCurrent(0); ui->progressBar->show(); ui->progressBar->showMax(); ui->progressBar->setState(ProgressBar::Play); if (progressTimer->isActive()) { progressTimer->stop(); progressTimer->start(); } else { progressTimer->start(); } ui->recordWidget->hide(); } /** * @brief 两路回放,以主通道的视频为主分别从HDMI-OUT0和HDMI-OUT1输出 */ void Widget::playTwoChannels(QString filename) { for (Channel* chn : channelList) { QString path = QString("%1/%2/%3").arg(Constant::VideoPath).arg(chn->channelName).arg(filename); int ret = chn->startPlayback(path); if (chn->channelName == Constant::MainChannel) { if (ret) { int duration = chn->playbackDuration; ui->progressBar->setDuration(duration); ui->progressBar->setCurrent(0); ui->progressBar->show(); ui->progressBar->showMax(); ui->progressBar->setState(ProgressBar::Play); if (progressTimer->isActive()) { progressTimer->stop(); progressTimer->start(); } else { progressTimer->start(); } ui->recordWidget->hide(); } else { ui->progressBar->hide(); ui->recordWidget->hide(); } } } curPlayFilename = filename; curPlayChannel = Constant::MainChannel; isPlayback = true; // 全局保存正在播放的视频 mutex.lock(); curFilename = filename; condition.wakeAll(); mutex.unlock(); } /** * @brief 视频跳转 */ 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(); } else { chn->back(); serialPortTool->onBack(); } if (chn->channelName == Constant::MainChannel) ui->progressBar->showMax(); } } } /** * @brief 当前视频播放完毕 */ void Widget::onPlayEnd() { // 当两路回放时,只处理一次槽函数 if (playbackMode == Constant::TwoChannelPlayback) { LinkObject* file = static_cast(sender()); for (Channel* chn : channelList) { if (chn->inputFile == file) { if (chn->channelName != Constant::MainChannel) { return; } } } } emit needPlayVideo("next"); } /** * @brief 显示录制状态的槽函数 * @param show 是否正在录制 */ void Widget::onShowRecordLabel(bool show) { Channel* chn = static_cast(sender()); QLabel* lblImg; QLabel* lblTxt; if (chn->channelName == Constant::MainChannel) { lblImg = ui->lblImgA; lblTxt = ui->lblTxtA; } else { lblImg = ui->lblImgB; lblTxt = ui->lblTxtB; } if (show) { lblImg->setPixmap(QPixmap(":/images/record.png")); lblTxt->setText("录制中"); } else { lblImg->setPixmap(QPixmap(":/images/no-record.png")); lblTxt->setText("未录制"); } } /** * @brief 根据名称查找通道 * @param name 通道名称 */ Channel* Widget::findChannelByName(QString name) { for (Channel* chn : channelList) { if (chn->channelName == name) { return chn; } } return nullptr; }