#include "mainwindowa.h" #include "common.h" #include #include #include #include "ffmpeg_init.h" #include "qimage_operation.h" #include "qscreen.h" #include "start_play_thread.h" #include "AvRecorder/ui/opengl_video_widget.h" #if NDEBUG #define AUTO_HIDE_PLAYCONTROL 1 // release version #else #define AUTO_HIDE_PLAYCONTROL 0 #endif MainWindowA::MainWindowA(QWidget* parent) : QMainWindow(parent) { m_playerController = new PlayerController; // 1. 菜单栏和主菜单 m_menuBar = new QMenuBar(this); setMenuBar(m_menuBar); // 文件菜单 m_menuFile = new QMenu(tr("文件"), this); m_menuBar->addMenu(m_menuFile); m_actionOpen = new QAction(tr("打开"), this); m_actionQuit = new QAction(tr("退出"), this); m_menuFile->addAction(m_actionOpen); m_menuFile->addSeparator(); m_menuFile->addAction(m_actionQuit); connect(m_actionOpen, &QAction::triggered, this, &MainWindowA::on_actionOpen_triggered); connect(m_actionQuit, &QAction::triggered, this, &MainWindowA::on_actionQuit_triggered); // 最近文件菜单 m_menuRecentFiles = new QMenu(tr("最近文件"), this); m_menuBar->addMenu(m_menuRecentFiles); // 播放列表菜单 m_menuSavedPlaylist = new QMenu(tr("播放列表"), this); m_menuBar->addMenu(m_menuSavedPlaylist); // CV菜单 m_menuCV = new QMenu(tr("图像处理"), this); m_menuBar->addMenu(m_menuCV); // 样式菜单 m_menuStyle = new QMenu(tr("样式"), this); m_menuBar->addMenu(m_menuStyle); // 音频可视化菜单 m_menuAudioVisualize = new QMenu(tr("音频可视化"), this); m_menuBar->addMenu(m_menuAudioVisualize); // 帮助菜单 m_menuHelp = new QMenu(tr("帮助"), this); m_menuBar->addMenu(m_menuHelp); m_actionHelp = new QAction(tr("帮助"), this); m_actionAbout = new QAction(tr("关于"), this); m_actionAbout_QT = new QAction(tr("关于Qt"), this); m_menuHelp->addAction(m_actionHelp); m_menuHelp->addAction(m_actionAbout); m_menuHelp->addAction(m_actionAbout_QT); connect(m_actionHelp, &QAction::triggered, this, &MainWindowA::on_actionHelp_triggered); connect(m_actionAbout, &QAction::triggered, this, &MainWindowA::on_actionAbout_triggered); connect(m_actionAbout_QT, &QAction::triggered, qApp, &QApplication::aboutQt); // 2. 主控件和状态栏 m_centralWidget = new QWidget(this); setCentralWidget(m_centralWidget); m_statusBar = new QStatusBar(this); setStatusBar(m_statusBar); // 3. 其他Action初始化 m_actionStop = new QAction(tr("停止"), this); m_actionFullscreen = new QAction(tr("全屏"), this); m_actionFullscreen->setCheckable(true); m_actionHide_Play_Ctronl = new QAction(tr("隐藏控制栏"), this); m_actionHide_Play_Ctronl->setCheckable(true); m_actionAspect_Ratio = new QAction(tr("保持比例"), this); m_actionLoop_Play = new QAction(tr("循环播放"), this); m_actionLoop_Play->setCheckable(true); m_actionMedia_Info = new QAction(tr("媒体信息"), this); m_actionKeyboard_Usage = new QAction(tr("快捷键说明"), this); m_actionPlayList = new QAction(tr("播放列表窗口"), this); m_actionPlayList->setCheckable(true); m_actionOpenNetworkUrl = new QAction(tr("打开网络地址"), this); m_actionOriginalSize = new QAction(tr("原始大小"), this); m_actionHardware_decode = new QAction(tr("硬件解码"), this); m_actionHardware_decode->setCheckable(true); // 4. CV菜单Action m_actionGrayscale = new QAction(tr("灰度"), this); m_actionGrayscale->setCheckable(true); m_actionMirro = new QAction(tr("镜像"), this); m_actionMirro->setCheckable(true); m_actionTransform = new QAction(tr("变换"), this); m_actionTransform->setCheckable(true); m_menuCV->addAction(m_actionGrayscale); m_menuCV->addAction(m_actionMirro); m_menuCV->addAction(m_actionTransform); m_menuCV->addSeparator(); m_actionRotate = new QAction(tr("旋转"), this); m_actionRotate->setCheckable(true); m_actionRepeat = new QAction(tr("重复"), this); m_actionRepeat->setCheckable(true); m_actionEqualizeHist = new QAction(tr("直方图均衡"), this); m_actionEqualizeHist->setCheckable(true); m_actionThreshold = new QAction(tr("二值化"), this); m_actionThreshold->setCheckable(true); m_actionThreshold_Adaptive = new QAction(tr("自适应阈值"), this); m_actionThreshold_Adaptive->setCheckable(true); m_actionReverse = new QAction(tr("反色"), this); m_actionReverse->setCheckable(true); m_actionColorReduce = new QAction(tr("色彩减少"), this); m_actionColorReduce->setCheckable(true); m_actionGamma = new QAction(tr("伽马"), this); m_actionGamma->setCheckable(true); m_actionContrastBright = new QAction(tr("对比度/亮度"), this); m_actionContrastBright->setCheckable(true); m_actionBlur = new QAction(tr("模糊"), this); m_actionBlur->setCheckable(true); m_actionCanny = new QAction(tr("Canny"), this); m_actionCanny->setCheckable(true); m_actionSobel = new QAction(tr("Sobel"), this); m_actionSobel->setCheckable(true); m_actionLaplacian = new QAction(tr("Laplacian"), this); m_actionLaplacian->setCheckable(true); m_actionScharr = new QAction(tr("Scharr"), this); m_actionScharr->setCheckable(true); m_actionPrewitt = new QAction(tr("Prewitt"), this); m_actionPrewitt->setCheckable(true); m_actionRemoveCV = new QAction(tr("移除选择"), this); m_actionRemoveCV->setCheckable(true); m_actionTest_CV = new QAction(tr("测试CV"), this); m_actionTest_CV->setCheckable(true); m_menuCV->addAction(m_actionRotate); m_menuCV->addAction(m_actionRepeat); m_menuCV->addAction(m_actionEqualizeHist); m_menuCV->addAction(m_actionThreshold); m_menuCV->addAction(m_actionThreshold_Adaptive); m_menuCV->addAction(m_actionReverse); m_menuCV->addAction(m_actionColorReduce); m_menuCV->addAction(m_actionGamma); m_menuCV->addAction(m_actionContrastBright); m_menuCV->addAction(m_actionBlur); m_menuCV->addAction(m_actionCanny); m_menuCV->addAction(m_actionSobel); m_menuCV->addAction(m_actionLaplacian); m_menuCV->addAction(m_actionScharr); m_menuCV->addAction(m_actionPrewitt); m_menuCV->addAction(m_actionRemoveCV); m_menuCV->addSeparator(); m_menuCV->addAction(m_actionTest_CV); // 批量 connect CV 菜单下所有 QAction for (QAction* action : m_menuCV->actions()) { if (action && !action->isSeparator()) { connect(action, &QAction::toggled, this, &MainWindowA::onCvActionToggled); } } // 5. 音频可视化菜单Action m_actionLine = new QAction(tr("线形"), this); m_actionLine->setCheckable(true); m_actionBar = new QAction(tr("柱形"), this); m_actionBar->setCheckable(true); m_actionPie = new QAction(tr("饼形"), this); m_actionPie->setCheckable(true); m_actionSampling = new QAction(tr("采样"), this); m_actionSampling->setCheckable(true); m_actionFrequency = new QAction(tr("频率"), this); m_actionFrequency->setCheckable(true); m_menuAudioVisualize->addAction(m_actionLine); m_menuAudioVisualize->addAction(m_actionBar); m_menuAudioVisualize->addAction(m_actionPie); m_menuAudioVisualize->addSeparator(); m_menuAudioVisualize->addAction(m_actionSampling); m_menuAudioVisualize->addAction(m_actionFrequency); // 6. 分组 m_CvActsGroup = new QActionGroup(this); m_CvActsGroup->addAction(m_actionRotate); m_CvActsGroup->addAction(m_actionRepeat); m_CvActsGroup->addAction(m_actionEqualizeHist); m_CvActsGroup->addAction(m_actionThreshold); m_CvActsGroup->addAction(m_actionThreshold_Adaptive); m_CvActsGroup->addAction(m_actionReverse); m_CvActsGroup->addAction(m_actionColorReduce); m_CvActsGroup->addAction(m_actionGamma); m_CvActsGroup->addAction(m_actionContrastBright); m_CvActsGroup->addAction(m_actionCanny); m_CvActsGroup->addAction(m_actionBlur); m_CvActsGroup->addAction(m_actionSobel); m_CvActsGroup->addAction(m_actionLaplacian); m_CvActsGroup->addAction(m_actionScharr); m_CvActsGroup->addAction(m_actionPrewitt); m_CvActsGroup->addAction(m_actionRemoveCV); m_AVisualGrapicTypeActsGroup = new QActionGroup(this); m_AVisualGrapicTypeActsGroup->addAction(m_actionLine); m_AVisualGrapicTypeActsGroup->addAction(m_actionBar); m_AVisualGrapicTypeActsGroup->addAction(m_actionPie); m_AVisualTypeActsGroup = new QActionGroup(this); m_AVisualTypeActsGroup->addAction(m_actionSampling); m_AVisualTypeActsGroup->addAction(m_actionFrequency); // 7. 信号槽 connect(m_actionSampling, &QAction::triggered, this, &MainWindowA::popup_audio_effect); connect(m_actionFrequency, &QAction::triggered, this, &MainWindowA::popup_audio_effect); connect(m_actionLine, &QAction::triggered, this, &MainWindowA::popup_audio_effect); connect(m_actionBar, &QAction::triggered, this, &MainWindowA::popup_audio_effect); connect(m_actionPie, &QAction::triggered, this, &MainWindowA::popup_audio_effect); // ... 其余Action信号槽如有也可补全 ... // 8. 继续原有初始化流程 // setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint // | Qt::WindowCloseButtonHint); // 新增:主布局,视频+控制条 auto mainLayout = new QVBoxLayout(m_centralWidget); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); create_video_label(); create_play_control(); create_audio_effect(); if (m_video_widget) mainLayout->addWidget(m_video_widget.get(), 1); if (m_play_control_wnd) mainLayout->addWidget(m_play_control_wnd.get(), 0); mainLayout->addWidget(m_audio_effect_wnd.get(), 0); m_centralWidget->setLayout(mainLayout); setWindowTitle(tr("Video Player")); qApp->installEventFilter(this); setAcceptDrops(true); #if AUTO_HIDE_PLAYCONTROL setMouseTracking(true); m_timer.setInterval(3 * 1000); m_timer.setSingleShot(false); connect(&m_timer, &QTimer::timeout, this, &MainWindowA::check_hide_play_control); m_timer.start(); #endif read_settings(); update_menus(); #if !NDEBUG print_screen(); #endif resize(600, 600); connect(m_playerController, &PlayerController::startToPlaySignal, this, &MainWindowA::update_menus); connect(m_playerController, &PlayerController::frameReady, this, &MainWindowA::frameReady); connect(m_playerController, &PlayerController::audioData, this, &MainWindowA::audio_data); connect(m_playerController, &PlayerController::setPlayControlWnd, this, &MainWindowA::set_paly_control_wnd); connect(m_playerController, &PlayerController::updatePlayControlVolume, this, &MainWindowA::update_paly_control_volume); connect(m_playerController, &PlayerController::updatePlayControlStatus, this, &MainWindowA::update_paly_control_status); // 新增:连接UI相关信号 connect(m_playerController, &PlayerController::showMessage, this, &MainWindowA::onShowMessage); connect(m_playerController, &PlayerController::requestFullscreen, this, &MainWindowA::onRequestFullscreen); connect(m_playerController, &PlayerController::requestHideStatusBar, this, &MainWindowA::onRequestHideStatusBar); connect(m_playerController, &PlayerController::updatePlayTime, this, &MainWindowA::update_play_time); //connect(m_playerController, &PlayerController::playSeek, this, &MainWindowA::play_seek); hide_play_control(false); m_playerController->startToPlay("C:/Users/zhuizhu/Videos/2.mp4"); } MainWindowA::~MainWindowA() { m_playerController->stopPlay(); save_settings(); } QScreen* MainWindowA::screen() const { return QApplication::primaryScreen(); } QRect MainWindowA::screen_rect() const { //auto pScreen = screen(); //auto scale = pScreen->devicePixelRatio(); //return QRect(0, 0, rt.width() * scale, rt.height() * scale); return screen()->geometry(); } qreal MainWindowA::screen_scale() const { return screen()->devicePixelRatio(); } QSize MainWindowA::display_video_size(AVCodecContext* pVideo) const { auto scale = screen_scale(); //screen display scale if (pVideo && scale != 0) return QSize(pVideo->width / scale, pVideo->height / scale); return QSize(0, 0); } void MainWindowA::create_video_label() { m_video_widget = std::make_unique(centralWidget()); // 不再单独设置布局,统一在 centralWidget 的主布局中管理 } void MainWindowA::create_audio_effect() { m_audio_effect_wnd = std::make_unique(centralWidget()); m_audio_effect_wnd->setObjectName(QString::fromUtf8("audio_effect")); m_audio_effect_wnd->hide(); // connect(m_audio_effect_wnd.get(), &AudioEffectGL::hiden, this, &MainWindowA::start_send_data); connect(m_audio_effect_wnd.get(), &AudioEffectGL::hiden, m_playerController, &PlayerController::startSendData); } void MainWindowA::show_audio_effect(bool bShow) { if (!m_audio_effect_wnd) return; auto pt = frameGeometry().center() - m_audio_effect_wnd->rect().center(); m_audio_effect_wnd->move(pt); m_audio_effect_wnd->paint_clear(); if (bShow) { m_audio_effect_wnd->show(); } else { m_audio_effect_wnd->hide(); } } void MainWindowA::create_recentfiles_menu() { for (int i = 0; i < MaxRecentFiles; ++i) { m_recentFileActs[i] = std::make_unique(this); m_recentFileActs[i]->setVisible(false); connect(m_recentFileActs[i].get(), SIGNAL(triggered()), this, SLOT(open_recentFile())); } m_recentClear = std::make_unique(this); m_recentClear->setText(tr("清除")); connect(m_recentClear.get(), SIGNAL(triggered()), this, SLOT(clear_recentfiles())); auto pMenu = m_menuRecentFiles; pMenu->clear(); for (int i = 0; i < MaxRecentFiles; ++i) pMenu->addAction(m_recentFileActs[i].get()); pMenu->addSeparator(); pMenu->addAction(m_recentClear.get()); update_recentfile_actions(); } void MainWindowA::set_current_file(const QString& fileName) { setWindowFilePath(fileName); auto files = m_settings.get_recentfiles().toStringList(); files.removeAll(fileName); files.prepend(fileName); while (files.size() > MaxRecentFiles) files.removeLast(); m_settings.set_recentfiles(files); update_recentfile_actions(); } void MainWindowA::clear_recentfiles() { auto files = m_settings.get_recentfiles().toStringList(); files.clear(); m_settings.set_recentfiles(files); update_recentfile_actions(); } void MainWindowA::remove_recentfiles(const QString& fileName) { auto files = m_settings.get_recentfiles().toStringList(); files.removeAll(fileName); m_settings.set_recentfiles(files); update_recentfile_actions(); } void MainWindowA::update_recentfile_actions() { auto files = m_settings.get_recentfiles().toStringList(); int numRecentFiles = qMin(files.size(), (int) MaxRecentFiles); m_menuRecentFiles->setEnabled(numRecentFiles > 0); for (int i = 0; i < numRecentFiles; ++i) { QString text = tr("%1 %2").arg(i + 1).arg(stripped_name(files[i])); m_recentFileActs[i]->setText( QApplication::translate("MainWindowA", text.toStdString().c_str(), nullptr)); m_recentFileActs[i]->setData(files[i]); m_recentFileActs[i]->setVisible(true); } for (int j = numRecentFiles; j < MaxRecentFiles; ++j) m_recentFileActs[j]->setVisible(false); } QString MainWindowA::stripped_name(const QString& fullFileName) const { return QFileInfo(fullFileName).fileName(); } void MainWindowA::open_recentFile() { if (auto action = qobject_cast(sender())) m_playerController->startToPlay(action->data().toString()); } void MainWindowA::about_media_info() { // if (!m_pVideoState) // return; // auto pState = m_playerController->state(); // if (!pState) // return; // if (auto ic = pState->ic) { // auto str = dump_format(ic, 0, pState->filename); // show_msg_dlg(str, "Media information", "QLabel{min-width: 760px;}"); // } } void MainWindowA::create_play_control() { m_play_control_wnd = std::make_unique(m_playerController, this); m_play_control_wnd->setObjectName(QString::fromUtf8("play_control")); m_play_control_wnd->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); // 不再 setGeometry } void MainWindowA::update_video_label() { // 移除手动 resize,让布局自动管理 // auto sizeCenter = centralWidget()->size(); // if (auto pLabel = get_video_widget()) // pLabel->resize(sizeCenter.width(), sizeCenter.height()); } void MainWindowA::show_msg_dlg(const QString& message, const QString& windowTitle, const QString& styleSheet) { onShowMessage(message, windowTitle, styleSheet); } void MainWindowA::update_play_control() { // if (auto pPlayControl = get_play_control()) { // auto sizeCenter = centralWidget()->size(); // pPlayControl->resize(sizeCenter.width(), pPlayControl->size().height()); // auto frameGeoRt = frameGeometry(); // auto geoRt = geometry(); // // QPoint pt = ui->statusbar->pos(); // int borderH = frameGeoRt.height() - (geoRt.y() - frameGeoRt.y()) - geoRt.height(); // //int borderH = frameGeoRt.height() - geoRt.height(); // // int borderw = frameGeoRt.width() - geoRt.width(); // // int borderSelf = pPlayControl->frameGeometry().height() - (pPlayControl->geometry().y() - pPlayControl->frameGeometry().y()) - pPlayControl->geometry().height(); // //auto pt = geoRt.bottomLeft() - QPoint(0, szPlayControl.height() + borderH); // auto pt = geoRt.bottomLeft() - QPoint(0, pPlayControl->size().height() - 1); // pPlayControl->move(pt); // } } void MainWindowA::print_size() const { auto rt = geometry(); qDebug("geometry rt:(x:%d, y:%d, w:%d, h:%d)", rt.x(), rt.y(), rt.width(), rt.height()); rt = frameGeometry(); qDebug("frameGeometry rt:(x:%d, y:%d, w:%d, h:%d)", rt.x(), rt.y(), rt.width(), rt.height()); auto size = this->size(); qDebug("window size:(%d,%d)", size.width(), size.height()); // 这里不再有ui->centralwidget,直接用m_centralWidget size = m_centralWidget->size(); qDebug("centralwidget size:(%d,%d)", size.width(), size.height()); // 菜单栏 size = m_menuBar->size(); qDebug("menubar size:(%d,%d)", size.width(), size.height()); // 状态栏 size = m_statusBar->size(); qDebug("statusbar size:(%d,%d)", size.width(), size.height()); // 菜单栏位置 auto pt = m_menuBar->pos(); qDebug("menuBar pt (x:%d, y:%d)", pt.x(), pt.y()); } void MainWindowA::print_screen() const { auto screen = QApplication::primaryScreen(); auto rt = screen->availableGeometry(); qDebug("availableGeometry rt (x:%d, y:%d, width:%d, height:%d)", rt.x(), rt.y(), rt.width(), rt.height()); auto sz = screen->availableSize(); qDebug("availableSize sz (width:%d, height:%d)", sz.width(), sz.height()); sz = screen->size(); qDebug("size sz (width:%d, height:%d)", sz.width(), sz.height()); rt = screen->virtualGeometry(); qDebug("virtualGeometry rt (x:%d, y:%d, width:%d, height:%d)", rt.x(), rt.y(), rt.width(), rt.height()); sz = screen->virtualSize(); qDebug("virtualSize sz (width:%d, height:%d)", sz.width(), sz.height()); rt = screen->availableVirtualGeometry(); qDebug("availableVirtualGeometry rt (x:%d, y:%d, width:%d, height:%d)", rt.x(), rt.y(), rt.width(), rt.height()); sz = screen->availableVirtualSize(); qDebug("availableVirtualSize sz (width:%d, height:%d)", sz.width(), sz.height()); rt = screen->geometry(); qDebug("geometry rt (x:%d, y:%d, width:%d, height:%d)", rt.x(), rt.y(), rt.width(), rt.height()); auto depth = screen->depth(); qDebug() << "depth :" << depth; auto ratio = screen->devicePixelRatio(); qDebug() << "devicePixelRatio :" << ratio; auto dot_per_inch = screen->logicalDotsPerInch(); qDebug() << "logicalDotsPerInch :" << dot_per_inch; auto x = screen->logicalDotsPerInchX(); qDebug() << "logicalDotsPerInchX :" << x; auto y = screen->logicalDotsPerInchY(); qDebug() << "logicalDotsPerInchY :" << y; auto str = screen->manufacturer(); qDebug() << "manufacturer :" << str; str = screen->model(); qDebug() << "model :" << str; str = screen->name(); qDebug() << "name :" << str; str = screen->serialNumber(); qDebug() << "serialNumber :" << str; auto o = screen->nativeOrientation(); qDebug() << "nativeOrientation :" << o; o = screen->orientation(); qDebug() << "orientation :" << o; o = screen->primaryOrientation(); qDebug() << "primaryOrientation :" << o; auto ph_d = screen->physicalDotsPerInch(); qDebug() << "physicalDotsPerInch :" << ph_d; ph_d = screen->physicalDotsPerInchX(); qDebug() << "physicalDotsPerInchX :" << ph_d; ph_d = screen->physicalDotsPerInchY(); qDebug() << "physicalDotsPerInchY :" << ph_d; auto sz_f = screen->physicalSize(); qDebug() << "physicalSize :" << sz_f; auto fr = screen->refreshRate(); qDebug() << "refreshRate :" << fr; } void MainWindowA::resizeEvent(QResizeEvent* event) { update_video_label(); update_play_control(); QMainWindow::resizeEvent(event); } void MainWindowA::moveEvent(QMoveEvent* event) { update_play_control(); QMainWindow::moveEvent(event); } void MainWindowA::keyPressEvent(QKeyEvent* event) { qDebug() << "Mainwindow key event, event:" << event->text() << "key:" << event->key() << "key_str:" << QKeySequence(event->key()).toString(); switch (event->key()) { case Qt::Key_Space: // pause/continue case Qt::Key_Up: // volume up case Qt::Key_Down: // volume down case Qt::Key_Left: // play back case Qt::Key_Right: // play forward case Qt::Key_M: // mute case Qt::Key_Comma: // speed down case Qt::Key_Period: // speed up play_control_key((Qt::Key) event->key()); break; case Qt::Key_A: // aspect ratio on_actionAspect_Ratio_triggered(); break; case Qt::Key_O: // keep orginal size on_actionOriginalSize_triggered(); break; case Qt::Key_L: // show play list wnd { show_playlist(); m_actionPlayList->setChecked(true); } break; case Qt::Key_F: // full screen { bool bFullscreen = label_fullscreen(); show_fullscreen(!bFullscreen); m_actionFullscreen->setChecked(!bFullscreen); } break; case Qt::Key_Escape: { show_fullscreen(false); m_actionFullscreen->setChecked(false); } break; case Qt::Key_H: on_actionKeyboard_Usage_triggered(); break; default: qDebug("Not handled key event, key:%s(%d) pressed!\n", qUtf8Printable(event->text()), event->key()); QWidget::keyPressEvent(event); break; } } bool MainWindowA::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::MouseMove) { auto mouseEvent = static_cast(event); // displayStatusMessage(QString("Mouse move // (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y())); check_hide_menubar(mouseEvent->pos()); #if AUTO_HIDE_PLAYCONTROL if (!(m_actionHide_Play_Ctronl->isChecked() || label_fullscreen())) { if (cursor_in_window(get_play_control())) { m_timer.stop(); auto_hide_play_control(false); } else { m_timer.start(); } } hide_cursor(false); setCursor(Qt::ArrowCursor); #endif } return QMainWindow::eventFilter(obj, event); } void MainWindowA::dropEvent(QDropEvent* event) { auto mimeData = event->mimeData(); if (!mimeData->hasUrls()) return; if (auto urlList = mimeData->urls(); urlList.size() > 0) m_playerController->startToPlay(urlList.at(0).toLocalFile()); } void MainWindowA::dragEnterEvent(QDragEnterEvent* event) { if (auto mimeData = event->mimeData(); mimeData->hasUrls()) event->acceptProposedAction(); event->accept(); } void MainWindowA::check_hide_menubar(const QPoint& pt) { if (isFullScreen()) hide_menubar(pt.y() > menuBar()->geometry().height()); } void MainWindowA::check_hide_play_control() { if (!m_playerController->isPlaying()) return; if (!isFullScreen() && cursor_in_window(get_play_control())) { qDebug() << "Cursor is in PlayControl window, don't hide it."; return; } auto_hide_play_control(); hide_cursor(); } void MainWindowA::auto_hide_play_control(bool bHide) { if (!get_play_control()) return; if (!m_playerController->state()) return; if (m_actionHide_Play_Ctronl->isChecked()) return; hide_play_control(bHide); } void MainWindowA::on_actionOpen_triggered() { const QStringList filters( {"Videos (*.mp4 *.avi *.mkv)", "Audios (*.mp3 *.wav *.wma)", "Any files (*)"}); QFileDialog dialog(this); dialog.setFileMode(QFileDialog::ExistingFile); // dialog.setNameFilter(tr("Videos (*.mp4 *.avi *.mp3)")); dialog.setNameFilters(filters); dialog.setViewMode(QFileDialog::List); if (dialog.exec()) { m_playerController->startToPlay(dialog.selectedFiles()[0]); } } void MainWindowA::on_actionAspect_Ratio_triggered() {} void MainWindowA::on_actionQuit_triggered() { QMainWindow::close(); } void MainWindowA::on_actionHelp_triggered() {} void MainWindowA::on_actionStop_triggered() { m_playerController->stopPlay(); } void MainWindowA::on_actionHide_Play_Ctronl_triggered() { hide_play_control(m_actionHide_Play_Ctronl->isChecked()); } void MainWindowA::on_actionFullscreen_triggered() { show_fullscreen(m_actionFullscreen->isChecked()); } void MainWindowA::on_actionLoop_Play_triggered() { if (auto pState = m_playerController->state()) pState->loop = int(m_actionLoop_Play->isChecked()); } void MainWindowA::on_actionMedia_Info_triggered() { if (m_playerController->isPlaying()) about_media_info(); } void MainWindowA::on_actionKeyboard_Usage_triggered() { QString str; QString indent = " "; str += "A" + indent + "Video aspect ratio\n"; str += "F" + indent + "Fulllscreen/Unfullscreen\n"; str += "H" + indent + "Show help\n"; str += "L" + indent + "Show playlist\n"; str += "M" + indent + "Mute/Unmute\n"; str += "O" + indent + "Keep video original size\n"; str += "Space" + indent + "Pause/Play\n"; str += "Up" + indent + "Volume up\n"; str += "Down" + indent + "Volume down\n"; str += "Left" + indent + "Play back\n"; str += "Right" + indent + "Play forward\n"; str += "<" + indent + "Speed down\n"; str += ">" + indent + "Speed up\n"; show_msg_dlg(str, "Keyboard Control"); } void MainWindowA::set_audio_effect_format(const BarHelper::VisualFormat& fmt) { if (m_audio_effect_wnd) m_audio_effect_wnd->set_draw_fmt(fmt); } void MainWindowA::popup_audio_effect() { if (m_playerController->isPlaying()) { BarHelper::VisualFormat fmt; get_avisual_format(fmt); set_audio_effect_format(fmt); show_audio_effect(); m_playerController->startSendData(); } } void MainWindowA::center_window(QRect screen_rec) { auto x = (screen_rec.width() - width()) / 2; auto y = (screen_rec.height() - height()) / 2; move(x, y); show(); } void MainWindowA::show_fullscreen(bool bFullscreen) { onRequestFullscreen(bFullscreen); } bool MainWindowA::label_fullscreen() { if (auto pLabel = get_video_widget()) return pLabel->isFullScreen(); return false; } void MainWindowA::on_actionOriginalSize_triggered() { // if (!m_pVideoState) // return; // auto pVideoCtx = m_pVideoState->get_contex(AVMEDIA_TYPE_VIDEO); // auto pLabel = get_video_widget(); // if (!pVideoCtx || !pLabel) // return; // auto sizeLabel = pLabel->size(); // auto sz = size(); // auto video_sz = display_video_size(pVideoCtx); // int new_width = video_sz.width(); // int new_height = video_sz.height(); // if (new_width < minimumWidth()) { // new_height = minimumWidth() * new_height / new_width; // new_width = minimumWidth(); // } // if (new_height < minimumHeight()) { // new_width = minimumHeight() * new_width / new_height; // new_height = minimumHeight(); // } // int w_change = new_width - sizeLabel.width(); // int h_change = new_height - sizeLabel.height(); // sz += QSize(w_change, h_change); // resize_window(sz); } void MainWindowA::hide_play_control(bool bHide) { // if (auto pPlayControl = get_play_control()) { // // pPlayControl->setVisible(true); // // pPlayControl->setDisabled(false); // if (pPlayControl->isVisible() == bHide) { // pPlayControl->setVisible(!bHide); // } // } } void MainWindowA::set_paly_control_wnd(bool set) { auto pPlayControl = get_play_control(); if (!pPlayControl) return; if (set) { auto pState = m_playerController->state(); if (!pState) return; if (auto ic = pState->ic) { int64_t hours, mins, secs, us; get_duration_time(ic->duration, hours, mins, secs, us); pPlayControl->set_total_time(hours, mins, secs); } } else { pPlayControl->clear_all(); } } void MainWindowA::set_volume_updown(bool bUp, float unit) { auto volume = m_playerController->deviceVolume(); auto n_volume = volume; if (bUp) { n_volume += unit; } else { n_volume -= unit; } if (n_volume > 1.0 || n_volume < 0) { QApplication::beep(); } n_volume = n_volume > 1.0 ? 1.0 : n_volume; n_volume = n_volume < 0 ? 0 : n_volume; set_volume(int(n_volume * 100)); update_paly_control_volume(); } void MainWindowA::update_paly_control_volume() { if (auto pPlayControl = get_play_control()) pPlayControl->set_volume_slider(m_playerController->deviceVolume()); } void MainWindowA::update_paly_control_muted() { if (auto pPlayControl = get_play_control()) { if (auto pState = m_playerController->state()) pPlayControl->volume_muted(pState->muted); } } void MainWindowA::update_paly_control_status() { if (auto pPlayControl = get_play_control()) { if (auto pState = m_playerController->state()) pPlayControl->update_btn_play(!!pState->paused); } } void MainWindowA::update_play_time() { if (auto pPlayControl = get_play_control()) { // pPlayControl->setVisible(true); // pPlayControl->resize(800, 200); // pPlayControl->show(); if (auto pState = m_playerController->state()) pPlayControl->update_play_time(pState->audio_clock); } } void MainWindowA::play_seek() { if (auto pPlayControl = get_play_control()) { auto maxValue = pPlayControl->get_progress_slider_max(); auto total_time = pPlayControl->get_total_time(); auto value = pPlayControl->get_progress_slider_value(); double seek_time = 0; if (maxValue > 0) seek_time = value * total_time * 1.0 / maxValue; qDebug() << "val:" << value << ",maxVal:" << maxValue << ",total time" << total_time << ",seek time:" << seek_time; m_playerController->videoSeek(seek_time); } update_paly_control_status(); } void MainWindowA::play_mute(bool mute) { auto pState = m_playerController->state(); if (pState) toggle_mute(pState, mute); } void MainWindowA::set_volume(int volume) { auto pPlayControl = get_play_control(); if (!pPlayControl) return; auto max_val = pPlayControl->get_volum_slider_max(); auto vol = volume * 1.0 / max_val; m_playerController->setDeviceVolume(vol); volume_settings(true, vol); } void MainWindowA::set_play_speed() { auto pPlayControl = get_play_control(); if (!pPlayControl) return; auto speed = pPlayControl->get_speed(); qDebug("set_play_spped, speed control changed, speed:%d", speed); if (m_playerController) { if (auto pState = m_playerController->state()) { #if USE_AVFILTER_AUDIO set_audio_playspeed(pState, speed); #endif } } } void MainWindowA::play_speed_adjust(bool up) { if (auto pPlayControl = get_play_control()) pPlayControl->speed_adjust(up); set_play_speed(); } void MainWindowA::hide_statusbar(bool bHide) { onRequestHideStatusBar(bHide); } void MainWindowA::hide_menubar(bool bHide) { menuBar()->setVisible(!bHide); // qDebug("is full screen:%d, menu is visible:%d", isFullScreen(), bVisible); if (isFullScreen()) { centralWidget()->resize(centralWidget()->size()); } update_play_control(); } void MainWindowA::on_actionAbout_triggered() {} void MainWindowA::play_failed(const QString& file) { show_msg_dlg(QString("File play failed, file: %1").arg(toNativePath(file))); } void MainWindowA::play_start_seek() { play_seek(); m_playerController->pausePlay(); } void MainWindowA::play_control_key(Qt::Key key) { if (!m_playerController) return; auto pState = m_playerController->state(); if (!pState) return; switch (key) { case Qt::Key_Space: // pause/continue m_playerController->pausePlay(); break; case Qt::Key_M: toggle_mute(pState, !pState->muted); update_paly_control_muted(); break; case Qt::Key_Up: // volume set_volume_updown(true); break; case Qt::Key_Down: // volume set_volume_updown(false); break; case Qt::Key_Left: m_playerController->playSeekPre(); break; case Qt::Key_Right: m_playerController->playSeekNext(); break; case Qt::Key_Comma: play_speed_adjust(false); break; case Qt::Key_Period: play_speed_adjust(true); break; default: qDebug("key:(%d) pressed, not handled!\n", key); break; } } void MainWindowA::frameReady(AVFrame* frame) { // 添加空指针检查和frame有效性检查 if (!frame || !frame->data[0] || frame->width <= 0 || frame->height <= 0) { return; } auto widget = get_video_widget(); if (widget) { widget->Render(frame); } } void MainWindowA::subtitle_ready(const QString& text) { set_subtitle(text); } void MainWindowA::set_subtitle(const QString& str) { m_subtitle = str; qDebug() << "subtitle received:" << m_subtitle; } void MainWindowA::clear_subtitle_str() { set_subtitle(""); } void MainWindowA::displayStatusMessage(const QString& message) { int timeout = 0; // 5000: 5 second timeout if (auto bar = statusBar()) bar->showMessage(message, timeout); } void MainWindowA::print_decodeContext(const AVCodecContext* pDecodeCtx, bool bVideo) const { if (!pDecodeCtx) return; if (bVideo) { qInfo("video codec_name: %s", pDecodeCtx->codec->name); qInfo("codec_type: %d, codec_id: %d, codec_tag: %d", pDecodeCtx->codec_type, pDecodeCtx->codec_id, pDecodeCtx->codec_tag); qInfo("width: %d, height: %d, codec_tag: %d", pDecodeCtx->width, pDecodeCtx->height); } else { qInfo("audio codec_name: %s", pDecodeCtx->codec->name); qInfo("codec_type: %d, codec_id: %d, codec_tag: %d", pDecodeCtx->codec_type, pDecodeCtx->codec_id, pDecodeCtx->codec_tag); qInfo("sample_rate: %d, channels: %d, sample_fmt: %d", pDecodeCtx->sample_rate, pDecodeCtx->ch_layout.nb_channels, pDecodeCtx->sample_fmt); qInfo("frame_size: %d, frame_number: %d, block_align: %d", pDecodeCtx->frame_size, pDecodeCtx->frame_num, pDecodeCtx->block_align); } } void MainWindowA::save_settings() { auto res = m_actionHide_Play_Ctronl->isChecked(); m_settings.set_general("hidePlayContrl", int(res)); res = m_actionFullscreen->isChecked(); m_settings.set_general("fullScreen", int(res)); res = m_actionHardware_decode->isChecked(); m_settings.set_general("openDXVA2", int(res)); res = m_actionLoop_Play->isChecked(); m_settings.set_general("loopPlay", int(res)); m_settings.set_general("style", get_selected_style()); m_settings.set_info("software", "Video player"); //m_settings.set_info("version", PLAYER_VERSION); m_settings.set_info("author", "Steven Huang"); } void MainWindowA::read_settings() { int value; auto values = m_settings.get_general("hidePlayContrl"); if (values.isValid()) { value = values.toInt(); m_actionHide_Play_Ctronl->setChecked(!!value); hide_play_control(value); } values = m_settings.get_general("fullScreen"); if (values.isValid()) { value = values.toInt(); m_actionFullscreen->setChecked(!!value); show_fullscreen(value); } values = m_settings.get_general("openDXVA2"); if (values.isValid()) { value = values.toInt(); m_actionHardware_decode->setChecked(!!value); } values = m_settings.get_general("loopPlay"); if (values.isValid()) { value = values.toInt(); m_actionLoop_Play->setChecked(!!value); } } float MainWindowA::volume_settings(bool set, float vol) { if (set) { m_settings.set_general("volume", QString::number(float(vol), 'f', 1)); } else { auto value = 0.2f; // default sound volume auto values = m_settings.get_general("volume"); if (values.isValid()) value = values.toFloat(); return value; } return 0; } QString MainWindowA::get_selected_style() const { auto pMenu = m_menuStyle; for (auto action : pMenu->actions()) { if (!(action->isSeparator() || action->menu())) { qDebug("action: %s", qUtf8Printable(action->text())); if (action->isChecked()) return action->data().toString(); } } return QString(""); } void MainWindowA::set_style_action(const QString& style) { auto pMenu = m_menuStyle; for (auto action : pMenu->actions()) { if (!(action->isSeparator() || action->menu())) { if (action->data().toString() == style) action->setChecked(true); } } } void MainWindowA::audio_data(const AudioData& data) { if (m_audio_effect_wnd) m_audio_effect_wnd->paint_data(data); } void MainWindowA::update_menus() { qDebug() << "update_menus: " << m_playerController->isPlaying(); enable_menus(m_playerController->isPlaying()); enable_v_menus(m_playerController->playingHasVideo()); enable_a_menus(m_playerController->playingHasAudio()); } void MainWindowA::enable_menus(bool enable) { m_actionStop->setEnabled(enable); m_actionMedia_Info->setEnabled(enable); } void MainWindowA::enable_v_menus(bool enable) { m_actionAspect_Ratio->setEnabled(enable); m_actionOriginalSize->setEnabled(enable); m_actionHardware_decode->setEnabled(enable); for (auto& pAction : m_menuCV->actions()) { if (pAction) pAction->setEnabled(enable); } } void MainWindowA::enable_a_menus(bool enable) { m_menuAudioVisualize->setEnabled(enable); } bool MainWindowA::get_avisual_format(BarHelper::VisualFormat& fmt) const { if (m_actionLine->isChecked()) { fmt.gType = BarHelper::e_GtLine; } else if (m_actionBar->isChecked()) { fmt.gType = BarHelper::e_GtBar; } else if (m_actionPie->isChecked()) { fmt.gType = BarHelper::e_GtPie; } if (m_actionSampling->isChecked()) { fmt.vType = BarHelper::e_VtSampleing; } else if (m_actionFrequency->isChecked()) { fmt.vType = BarHelper::e_VtFrequency; } return true; } void MainWindowA::create_playlist_wnd() { m_playListWnd = std::make_unique(this); connect(m_playListWnd.get(), &PlayListWnd::play_file, m_playerController, &PlayerController::startToPlay); // connect(m_playListWnd.get(), &PlayListWnd::save_playlist_signal, this, &MainWindowA::save_playlist); connect(m_playListWnd.get(), &PlayListWnd::hiden, this, &MainWindowA::playlist_hiden); connect(m_playListWnd.get(), &PlayListWnd::playlist_file_saved, this, &MainWindowA::playlist_file_saved); } void MainWindowA::on_actionPlayList_triggered() { show_playlist(m_actionPlayList->isChecked()); } void MainWindowA::show_playlist(bool show) { if (!m_playListWnd) return; if (show) { m_playListWnd->show(); m_playListWnd->set_cur_palyingfile(); } else { m_playListWnd->hide(); } } void MainWindowA::playlist_hiden() { m_actionPlayList->setChecked(false); } void MainWindowA::add_to_playlist(const QString& file) { if (m_playListWnd) m_playListWnd->add_file(file); } QString MainWindowA::get_playingfile() const { if (m_playerController->isPlaying()) return m_videoFile; return QString(""); } void MainWindowA::on_actionOpenNetworkUrl_triggered() { NetworkUrlDlg dialog(this); if (dialog.exec() == QDialog::Accepted) { if (auto url = dialog.get_url(); !url.isEmpty()) { m_playerController->startToPlay(url); } else { show_msg_dlg("Please input a valid youtube url. "); } } } void MainWindowA::hide_cursor(bool bHide) { // if (bHide) { // QApplication::setOverrideCursor(Qt::BlankCursor); // } else { // QGuiApplication::restoreOverrideCursor(); // } } bool MainWindowA::cursor_in_window(QWidget* pWnd) { if (!pWnd) return false; auto rt = pWnd->rect(); return rt.contains(pWnd->mapFromGlobal(QCursor::pos())); } void MainWindowA::create_savedPlaylists_menu() { for (int i = 0; i < MaxPlaylist; ++i) { m_savedPlaylists[i] = std::make_unique(this); m_savedPlaylists[i]->setVisible(false); connect(m_savedPlaylists[i].get(), SIGNAL(triggered()), this, SLOT(open_playlist())); } m_PlaylistsClear = std::make_unique(this); m_PlaylistsClear->setText(tr("清除")); connect(m_PlaylistsClear.get(), SIGNAL(triggered()), this, SLOT(clear_savedPlaylists())); auto pMenu = m_menuSavedPlaylist; pMenu->clear(); for (int i = 0; i < MaxPlaylist; ++i) pMenu->addAction(m_savedPlaylists[i].get()); pMenu->addSeparator(); pMenu->addAction(m_PlaylistsClear.get()); update_savedPlaylists_actions(); } void MainWindowA::remove_playlist_file(const QString& fileName) { auto files = m_settings.get_savedplaylists().toStringList(); files.removeAll(fileName); m_settings.set_savedplaylists(files); update_savedPlaylists_actions(); } void MainWindowA::update_savedPlaylists_actions() { auto files = m_settings.get_savedplaylists().toStringList(); int num = qMin(files.size(), (int) MaxPlaylist); m_menuSavedPlaylist->setEnabled(num > 0); for (int i = 0; i < num; ++i) { QString text = tr("%1 %2").arg(i + 1).arg(stripped_name(files[i])); m_savedPlaylists[i]->setText( QApplication::translate("MainWindowA", text.toStdString().c_str(), nullptr)); m_savedPlaylists[i]->setData(files[i]); m_savedPlaylists[i]->setVisible(true); } for (int j = num; j < MaxPlaylist; ++j) m_savedPlaylists[j]->setVisible(false); } void MainWindowA::clear_savedPlaylists() { auto files = m_settings.get_savedplaylists().toStringList(); for (const auto& i : files) { QFile file(i); file.remove(); } files.clear(); m_settings.set_savedplaylists(files); update_savedPlaylists_actions(); } void MainWindowA::open_playlist() { if (!m_playListWnd) return; auto action = qobject_cast(sender()); if (!action) return; auto file = action->data().toString(); QStringList files; if (read_playlist(file, files)) { m_playListWnd->update_files(files); show_playlist(); m_actionPlayList->setChecked(true); } else { remove_playlist_file(file); } } void MainWindowA::playlist_file_saved(const QString& file) { auto files = m_settings.get_savedplaylists().toStringList(); files.removeAll(file); files.prepend(file); if (files.size() > MaxPlaylist) { show_msg_dlg(QString("You can only save %1 playlist files!").arg(MaxPlaylist)); } while (files.size() > MaxPlaylist) files.removeLast(); m_settings.set_savedplaylists(files); update_savedPlaylists_actions(); } bool MainWindowA::read_playlist(const QString& playlist_file, QStringList& files) const { QFile file(playlist_file); if (file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); stream.setCodec("UTF-8"); files = stream.readAll().split(PLAYLIST_SEPERATE_CHAR); files.removeAll(QString("")); file.close(); return true; } return false; } // ========== CV菜单Action统一处理槽 ========== void MainWindowA::onCvActionToggled() { if (!m_video_widget) return; // 灰度 m_video_widget->setGray(m_actionGrayscale && m_actionGrayscale->isChecked()); // 二值化 m_video_widget->setThreshold(m_actionThreshold && m_actionThreshold->isChecked(), 0.5f); // 模糊 m_video_widget->setBlur(m_actionBlur && m_actionBlur->isChecked(), 1.0f); // 反色 m_video_widget->setReverse(m_actionReverse && m_actionReverse->isChecked()); // 色彩减少 m_video_widget->setColorReduce(m_actionColorReduce && m_actionColorReduce->isChecked(), 8); // 伽马 m_video_widget->setGamma(m_actionGamma && m_actionGamma->isChecked(), 1.2f); // 对比度/亮度 m_video_widget->setContrastBright(m_actionContrastBright && m_actionContrastBright->isChecked(), 1.2f, 0.1f); // 镜像 m_video_widget->setMirror(m_actionMirro && m_actionMirro->isChecked()); // 其它特效可继续扩展 } // 新增槽函数实现 void MainWindowA::onShowMessage(const QString& message, const QString& windowTitle, const QString& styleSheet) { QMessageBox msgBox; msgBox.setText(message); msgBox.setWindowTitle(windowTitle); msgBox.setStyleSheet(styleSheet); msgBox.show(); msgBox.move(frameGeometry().center() - msgBox.rect().center()); msgBox.setWindowFlags(msgBox.windowFlags() | Qt::Dialog); msgBox.setModal(true); msgBox.exec(); } void MainWindowA::onRequestFullscreen(bool bFullscreen) { if (bFullscreen) { showFullScreen(); } else { showNormal(); update_video_label(); } hide_cursor(bFullscreen); } void MainWindowA::onRequestHideStatusBar(bool bHide) { statusBar()->setVisible(!bHide); auto sz_status = statusBar()->size(); if (isFullScreen()) { centralWidget()->resize(centralWidget()->size()); } else { auto sz = size(); if (statusBar()->isVisible()) { sz += QSize(0, sz_status.height()); } else { sz -= QSize(0, sz_status.height()); } resize(sz); } }