#include "mainwindow.h" #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_updatingSeek(false) { setWindowTitle("Zero-Copy CUDA-GL Video Player"); resize(960, 600); m_glWidget = new GLWidget(this); m_videoDecoder = new VideoDecoder(this); m_glWidget->setVideoDecoder(m_videoDecoder); setupUI(); // Conectar las señales de posición y finalización del hilo descodificador connect(m_videoDecoder, &VideoDecoder::positionChanged, this, &MainWindow::onPositionChanged); connect(m_videoDecoder, &VideoDecoder::playbackFinished, this, &MainWindow::onPlaybackFinished); } MainWindow::~MainWindow() { m_videoDecoder->stopThread(); } void MainWindow::setupUI() { // Aplicar hoja de estilos (QSS) para un look oscuro premium y retro-futurista this->setStyleSheet( "QMainWindow { background-color: #08080f; }" "QWidget { color: #f0f0f5; font-family: 'Outfit', 'Segoe UI', sans-serif; font-size: 13px; }" "QPushButton { background-color: #ff007f; color: white; border: none; padding: 8px 15px; border-radius: 6px; font-weight: bold; min-width: 60px; }" "QPushButton:hover { background-color: #ff3399; }" "QPushButton:pressed { background-color: #cc0066; }" "QPushButton:disabled { background-color: #444; color: #888; }" "QSlider::groove:horizontal { border: 1px solid #2d2d44; height: 6px; background: #1a1a2e; border-radius: 3px; }" "QSlider::sub-page:horizontal { background: #ff007f; border-radius: 3px; }" "QSlider::handle:horizontal { background: #ffffff; border: 1px solid #ff007f; width: 14px; height: 14px; margin: -4px 0; border-radius: 7px; }" "QSlider::handle:horizontal:hover { background: #ff007f; }" "QLabel { color: #a0a0c0; }" ); QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget); mainLayout->setContentsMargins(10, 10, 10, 10); mainLayout->setSpacing(10); mainLayout->addWidget(m_glWidget, 1); // Controles Multimedia QHBoxLayout *controlsLayout = new QHBoxLayout(); QPushButton *openBtn = new QPushButton("Abrir Video", this); openBtn->setStyleSheet("background-color: #00bfff;"); connect(openBtn, &QPushButton::clicked, this, &MainWindow::openVideoFile); controlsLayout->addWidget(openBtn); m_playBtn = new QPushButton("▶", this); connect(m_playBtn, &QPushButton::clicked, this, &MainWindow::togglePlayPause); controlsLayout->addWidget(m_playBtn); m_muteBtn = new QPushButton("🔊", this); m_muteBtn->setStyleSheet("background-color: #4a4e69;"); connect(m_muteBtn, &QPushButton::clicked, this, &MainWindow::toggleMute); controlsLayout->addWidget(m_muteBtn); m_seekBar = new QSlider(Qt::Horizontal, this); m_seekBar->setRange(0, 1000); m_seekBar->setEnabled(false); connect(m_seekBar, &QSlider::sliderMoved, this, &MainWindow::setVideoPosition); controlsLayout->addWidget(m_seekBar, 1); m_timeLabel = new QLabel("00:00 / 00:00", this); m_timeLabel->setMinimumWidth(90); m_timeLabel->setAlignment(Qt::AlignCenter); controlsLayout->addWidget(m_timeLabel); mainLayout->addLayout(controlsLayout); } void MainWindow::openVideoFile() { QString fileName = QFileDialog::getOpenFileName(this, "Abrir archivo de video", "", "Videos (*.mp4 *.avi *.mkv *.webm *.mov)"); if (!fileName.isEmpty()) { openVideoFileDirect(fileName); } } void MainWindow::openVideoFileDirect(const QString &fileName) { m_glWidget->clearVideo(); m_videoDecoder->stopThread(); if (m_videoDecoder->openFile(fileName)) { m_seekBar->setEnabled(m_videoDecoder->getDuration() > 0.0); m_playBtn->setText("⏸"); m_videoDecoder->start(); // Arranca el hilo de decodificación m_videoDecoder->play(); // Inicia la reproducción } } void MainWindow::togglePlayPause() { if (m_videoDecoder->isPaused()) { m_videoDecoder->play(); m_playBtn->setText("⏸"); } else { m_videoDecoder->pause(); m_playBtn->setText("▶"); } } void MainWindow::toggleMute() { static bool muted = false; muted = !muted; m_muteBtn->setText(muted ? "🔇" : "🔊"); } void MainWindow::setVideoPosition(int position) { if (m_videoDecoder->getDuration() > 0.0) { m_updatingSeek = true; double targetSecs = (static_cast(position) / 1000.0) * m_videoDecoder->getDuration(); m_videoDecoder->seek(targetSecs); m_updatingSeek = false; } } void MainWindow::onPositionChanged(qint64 positionMs) { double durationSecs = m_videoDecoder->getDuration(); if (durationSecs > 0.0 && !m_updatingSeek) { m_updatingSeek = true; double progress = static_cast(positionMs) / (durationSecs * 1000.0); m_seekBar->setValue(static_cast(progress * 1000.0)); m_updatingSeek = false; } // Formatear tiempos auto format = [](qint64 ms) -> QString { qint64 totalSecs = ms / 1000; int mins = totalSecs / 60; int secs = totalSecs % 60; return QString("%1:%2").arg(mins, 2, 10, QChar('0')).arg(secs, 2, 10, QChar('0')); }; m_timeLabel->setText(format(positionMs) + " / " + format(static_cast(durationSecs * 1000.0))); } void MainWindow::onPlaybackFinished() { m_playBtn->setText("▶"); m_seekBar->setValue(0); }