/****************************************************************************** QtAV Player Demo: this file is part of QtAV examples Copyright (C) 2012-2015 Wang Bin * This file is part of QtAV This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ #include "MainWindow.h" #include "EventFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ClickableMenu.h" #include "Slider.h" #include "StatisticsView.h" #include "TVView.h" #include "config/DecoderConfigPage.h" #include "config/VideoEQConfigPage.h" #include "config/ConfigDialog.h" #include "filters/OSDFilter.h" //#include "filters/AVFilterSubtitle.h" #include "playlist/PlayList.h" #include "../common/common.h" /* *TODO: * disable a/v actions if player is 0; * use action's value to set player's parameters when start to play a new file */ #define AVDEBUG() \ qDebug("%s %s @%d", __FILE__, __FUNCTION__, __LINE__); using namespace QtAV; const qreal kVolumeInterval = 0.04; extern QStringList idsToNames(QVector ids); extern QVector idsFromNames(const QStringList& names); void QLabelSetElideText(QLabel *label, QString text, int W = 0) { QFontMetrics metrix(label->font()); int width = label->width() - label->indent() - label->margin(); if (W || label->parent()) { int w = W; if (!w) w = ((QWidget*)label->parent())->width(); width = qMax(w - label->indent() - label->margin() - 13*(30), 0); //TODO: why 30? } QString clippedText = metrix.elidedText(text, Qt::ElideRight, width); label->setText(clippedText); } MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , mIsReady(false) , mHasPendingPlay(false) , mControlOn(false) , mShowControl(2) , mRepeateMax(0) , mpPlayer(0) , mpRenderer(0) , mpTempRenderer(0) , mpVideoFilter(0) , mpAudioFilter(0) , mpStatisticsView(0) , mpOSD(0) , mpSubtitle(0) , m_preview(0) { setWindowIcon(QIcon(QString::fromLatin1(":/QtAV.svg"))); mpOSD = new OSDFilterQPainter(this); mpSubtitle = new SubtitleFilter(this); mpChannelAction = 0; mpChannelMenu = 0; mpAudioTrackAction = 0; setMouseTracking(true); //mouseMoveEvent without press. connect(this, SIGNAL(ready()), SLOT(processPendingActions())); //QTimer::singleShot(10, this, SLOT(setupUi())); setupUi(); //setToolTip(tr("Click black area to use shortcut(see right click menu)")); WindowEventFilter *we = new WindowEventFilter(this); installEventFilter(we); connect(we, SIGNAL(fullscreenChanged()), SLOT(handleFullscreenChange())); } MainWindow::~MainWindow() { if (m_preview) { m_preview->close(); delete m_preview; } mpHistory->save(); mpPlayList->save(); if (mpVolumeSlider && !mpVolumeSlider->parentWidget()) { mpVolumeSlider->close(); delete mpVolumeSlider; mpVolumeSlider = 0; } if (mpStatisticsView) { delete mpStatisticsView; mpStatisticsView = 0; } } void MainWindow::initPlayer() { mpPlayer = new AVPlayer(this); mIsReady = true; //mpSubtitle->installTo(mpPlayer); //filter on frame mpSubtitle->setPlayer(mpPlayer); //mpPlayer->setAudioOutput(AudioOutputFactory::create(AudioOutputId_OpenAL)); EventFilter *ef = new EventFilter(mpPlayer); qApp->installEventFilter(ef); connect(ef, SIGNAL(helpRequested()), SLOT(help())); connect(ef, SIGNAL(showNextOSD()), SLOT(showNextOSD())); onCaptureConfigChanged(); onAVFilterVideoConfigChanged(); onAVFilterAudioConfigChanged(); connect(&Config::instance(), SIGNAL(captureDirChanged(QString)), SLOT(onCaptureConfigChanged())); connect(&Config::instance(), SIGNAL(captureFormatChanged(QString)), SLOT(onCaptureConfigChanged())); connect(&Config::instance(), SIGNAL(captureQualityChanged(int)), SLOT(onCaptureConfigChanged())); connect(&Config::instance(), SIGNAL(avfilterVideoChanged()), SLOT(onAVFilterVideoConfigChanged())); connect(&Config::instance(), SIGNAL(avfilterAudioChanged()), SLOT(onAVFilterAudioConfigChanged())); connect(&Config::instance(), SIGNAL(bufferValueChanged()), SLOT(onBufferValueChanged())); connect(&Config::instance(), SIGNAL(abortOnTimeoutChanged()), SLOT(onAbortOnTimeoutChanged())); connect(mpStopBtn, SIGNAL(clicked()), this, SLOT(stopUnload())); connect(mpForwardBtn, SIGNAL(clicked()), mpPlayer, SLOT(seekForward())); connect(mpBackwardBtn, SIGNAL(clicked()), mpPlayer, SLOT(seekBackward())); connect(mpVolumeBtn, SIGNAL(clicked()), SLOT(showHideVolumeBar())); connect(mpVolumeSlider, SIGNAL(sliderPressed()), SLOT(setVolume())); connect(mpVolumeSlider, SIGNAL(valueChanged(int)), SLOT(setVolume())); connect(mpPlayer, SIGNAL(seekFinished()), SLOT(onSeekFinished())); connect(mpPlayer, SIGNAL(mediaStatusChanged(QtAV::MediaStatus)), SLOT(onMediaStatusChanged())); connect(mpPlayer, SIGNAL(bufferProgressChanged(qreal)), SLOT(onBufferProgress(qreal))); connect(mpPlayer, SIGNAL(error(QtAV::AVError)), this, SLOT(handleError(QtAV::AVError))); connect(mpPlayer, SIGNAL(started()), this, SLOT(onStartPlay())); connect(mpPlayer, SIGNAL(stopped()), this, SLOT(onStopPlay())); connect(mpPlayer, SIGNAL(paused(bool)), this, SLOT(onPaused(bool))); connect(mpPlayer, SIGNAL(speedChanged(qreal)), this, SLOT(onSpeedChange(qreal))); connect(mpPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(onPositionChange(qint64))); //connect(mpPlayer, SIGNAL(volumeChanged(qreal)), SLOT(syncVolumeUi(qreal))); connect(mpVideoEQ, SIGNAL(brightnessChanged(int)), this, SLOT(onBrightnessChanged(int))); connect(mpVideoEQ, SIGNAL(contrastChanged(int)), this, SLOT(onContrastChanged(int))); connect(mpVideoEQ, SIGNAL(hueChanegd(int)), this, SLOT(onHueChanged(int))); connect(mpVideoEQ, SIGNAL(saturationChanged(int)), this, SLOT(onSaturationChanged(int))); connect(mpCaptureBtn, SIGNAL(clicked()), mpPlayer->videoCapture(), SLOT(request())); emit ready(); //emit this signal after connection. otherwise the slots may not be called for the first time } void MainWindow::onSeekFinished() { qDebug("seek finished at %lld", mpPlayer->position()); } void MainWindow::stopUnload() { mpPlayer->stop(); mpPlayer->unload(); } void MainWindow::setupUi() { QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->setSpacing(0); mainLayout->setMargin(0); setLayout(mainLayout); mpPlayerLayout = new QVBoxLayout(); mpControl = new QWidget(this); mpControl->setMaximumHeight(30); //mpPreview = new QLable(this); mpTimeSlider = new Slider(mpControl); mpTimeSlider->setDisabled(true); mpTimeSlider->setTracking(true); mpTimeSlider->setOrientation(Qt::Horizontal); mpTimeSlider->setMinimum(0); mpCurrent = new QLabel(mpControl); mpCurrent->setToolTip(tr("Current time")); mpCurrent->setMargin(2); mpCurrent->setText(QString::fromLatin1("00:00:00")); mpEnd = new QLabel(mpControl); mpEnd->setToolTip(tr("Duration")); mpEnd->setMargin(2); mpEnd->setText(QString::fromLatin1("00:00:00")); mpTitle = new QLabel(mpControl); mpTitle->setToolTip(tr("Render engine")); mpTitle->setText(QString::fromLatin1("QPainter")); mpTitle->setIndent(8); mpSpeed = new QLabel(QString::fromLatin1("1.00")); mpSpeed->setMargin(1); mpSpeed->setToolTip(tr("Speed. Ctrl+Up/Down")); mpPlayPauseBtn = new QToolButton(mpControl); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/play.svg"))); mpStopBtn = new QToolButton(mpControl); mpStopBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/stop.svg"))); mpBackwardBtn = new QToolButton(mpControl); mpBackwardBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/backward.svg"))); mpForwardBtn = new QToolButton(mpControl); mpForwardBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/forward.svg"))); mpOpenBtn = new QToolButton(mpControl); mpOpenBtn->setToolTip(tr("Open")); mpOpenBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/open.svg"))); mpInfoBtn = new QToolButton(); mpInfoBtn->setToolTip(QString::fromLatin1("Media information")); mpInfoBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/info.svg"))); mpCaptureBtn = new QToolButton(); mpCaptureBtn->setToolTip(tr("Capture")); mpCaptureBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/capture.svg"))); mpVolumeBtn = new QToolButton(); mpVolumeBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/sound.svg"))); mpVolumeSlider = new Slider(); mpVolumeSlider->hide(); mpVolumeSlider->setOrientation(Qt::Horizontal); mpVolumeSlider->setMinimum(0); const int kVolumeSliderMax = 100; mpVolumeSlider->setMaximum(kVolumeSliderMax); //mpVolumeSlider->setMaximumHeight(12); mpVolumeSlider->setMaximumWidth(88); mpVolumeSlider->setValue(int(1.0/kVolumeInterval*qreal(kVolumeSliderMax)/100.0)); setVolume(); mpMenuBtn = new QToolButton(); mpMenuBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/menu.svg"))); mpMenuBtn->setAutoRaise(true); mpMenuBtn->setPopupMode(QToolButton::InstantPopup); QMenu *subMenu = 0; QWidgetAction *pWA = 0; mpMenu = new QMenu(mpMenuBtn); mpMenu->addAction(tr("Open Url"), this, SLOT(openUrl())); //mpMenu->addAction(tr("Online channels"), this, SLOT(onTVMenuClick())); mpMenu->addSeparator(); subMenu = new QMenu(tr("Play list")); mpMenu->addMenu(subMenu); mpPlayList = new PlayList(this); mpPlayList->setSaveFile(Config::instance().defaultDir() + QString::fromLatin1("/playlist.qds")); mpPlayList->load(); connect(mpPlayList, SIGNAL(aboutToPlay(QString)), SLOT(play(QString))); pWA = new QWidgetAction(0); pWA->setDefaultWidget(mpPlayList); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? subMenu = new QMenu(tr("History")); mpMenu->addMenu(subMenu); mpHistory = new PlayList(this); mpHistory->setMaxRows(20); mpHistory->setSaveFile(Config::instance().defaultDir() + QString::fromLatin1("/history.qds")); mpHistory->load(); connect(mpHistory, SIGNAL(aboutToPlay(QString)), SLOT(play(QString))); pWA = new QWidgetAction(0); pWA->setDefaultWidget(mpHistory); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? mpMenu->addSeparator(); //mpMenu->addAction(tr("Report"))->setEnabled(false); //report bug, suggestions etc. using maillist? mpMenu->addAction(tr("About"), this, SLOT(about())); mpMenu->addAction(tr("Help"), this, SLOT(help())); mpMenu->addAction(tr("Donate"), this, SLOT(donate())); mpMenu->addAction(tr("Setup"), this, SLOT(setup())); mpMenu->addSeparator(); mpMenuBtn->setMenu(mpMenu); mpMenu->addSeparator(); subMenu = new QMenu(tr("Speed")); mpMenu->addMenu(subMenu); QDoubleSpinBox *pSpeedBox = new QDoubleSpinBox(0); pSpeedBox->setRange(0.01, 20); pSpeedBox->setValue(1.0); pSpeedBox->setSingleStep(0.01); pSpeedBox->setCorrectionMode(QAbstractSpinBox::CorrectToPreviousValue); pWA = new QWidgetAction(0); pWA->setDefaultWidget(pSpeedBox); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? subMenu = new ClickableMenu(tr("Repeat")); mpMenu->addMenu(subMenu); //subMenu->setEnabled(false); mpRepeatEnableAction = subMenu->addAction(tr("Enable")); mpRepeatEnableAction->setCheckable(true); connect(mpRepeatEnableAction, SIGNAL(toggled(bool)), SLOT(toggleRepeat(bool))); // TODO: move to a func or class mpRepeatBox = new QSpinBox(0); mpRepeatBox->setMinimum(-1); mpRepeatBox->setValue(-1); mpRepeatBox->setToolTip(QString::fromLatin1("-1: ") + tr("infinity")); connect(mpRepeatBox, SIGNAL(valueChanged(int)), SLOT(setRepeateMax(int))); QLabel *pRepeatLabel = new QLabel(tr("Times")); QHBoxLayout *hb = new QHBoxLayout; hb->addWidget(pRepeatLabel); hb->addWidget(mpRepeatBox); QVBoxLayout *vb = new QVBoxLayout; vb->addLayout(hb); pRepeatLabel = new QLabel(tr("From")); mpRepeatA = new QTimeEdit(); mpRepeatA->setDisplayFormat(QString::fromLatin1("HH:mm:ss")); mpRepeatA->setToolTip(tr("negative value means from the end")); connect(mpRepeatA, SIGNAL(timeChanged(QTime)), SLOT(repeatAChanged(QTime))); hb = new QHBoxLayout; hb->addWidget(pRepeatLabel); hb->addWidget(mpRepeatA); vb->addLayout(hb); pRepeatLabel = new QLabel(tr("To")); mpRepeatB = new QTimeEdit(); mpRepeatB->setDisplayFormat(QString::fromLatin1("HH:mm:ss")); mpRepeatB->setToolTip(tr("negative value means from the end")); connect(mpRepeatB, SIGNAL(timeChanged(QTime)), SLOT(repeatBChanged(QTime))); hb = new QHBoxLayout; hb->addWidget(pRepeatLabel); hb->addWidget(mpRepeatB); vb->addLayout(hb); QWidget *wgt = new QWidget; wgt->setLayout(vb); pWA = new QWidgetAction(0); pWA->setDefaultWidget(wgt); pWA->defaultWidget()->setEnabled(false); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? mpRepeatAction = pWA; mpMenu->addSeparator(); subMenu = new ClickableMenu(tr("Clock")); mpMenu->addMenu(subMenu); QActionGroup *ag = new QActionGroup(subMenu); ag->setExclusive(true); connect(subMenu, SIGNAL(triggered(QAction*)), SLOT(changeClockType(QAction*))); subMenu->addAction(tr("Auto"))->setData(-1); subMenu->addAction(tr("Audio"))->setData(AVClock::AudioClock); subMenu->addAction(tr("Video"))->setData(AVClock::VideoClock); foreach(QAction* action, subMenu->actions()) { action->setActionGroup(ag); action->setCheckable(true); } QAction *autoClockAction = subMenu->actions().at(0); autoClockAction->setChecked(true); autoClockAction->setToolTip(tr("Take effect in next playback")); subMenu = new ClickableMenu(tr("Subtitle")); mpMenu->addMenu(subMenu); QAction *act = subMenu->addAction(tr("Enable")); act->setCheckable(true); act->setChecked(mpSubtitle->isEnabled()); connect(act, SIGNAL(toggled(bool)), SLOT(toggoleSubtitleEnabled(bool))); act = subMenu->addAction(tr("Auto load")); act->setCheckable(true); act->setChecked(mpSubtitle->autoLoad()); connect(act, SIGNAL(toggled(bool)), SLOT(toggleSubtitleAutoLoad(bool))); subMenu->addAction(tr("Open"), this, SLOT(openSubtitle())); wgt = new QWidget(); hb = new QHBoxLayout(); wgt->setLayout(hb); hb->addWidget(new QLabel(tr("Engine"))); QComboBox *box = new QComboBox(); hb->addWidget(box); pWA = new QWidgetAction(0); pWA->setDefaultWidget(wgt); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? box->addItem(QString::fromLatin1("FFmpeg"), QString::fromLatin1("FFmpeg")); box->addItem(QString::fromLatin1("LibASS"), QString::fromLatin1("LibASS")); connect(box, SIGNAL(activated(QString)), SLOT(setSubtitleEngine(QString))); mpSubtitle->setEngines(QStringList() << box->itemData(box->currentIndex()).toString()); box->setToolTip(tr("FFmpeg supports more subtitles but only render plain text") + QString::fromLatin1("\n") + tr("LibASS supports ass styles")); wgt = new QWidget(); hb = new QHBoxLayout(); wgt->setLayout(hb); hb->addWidget(new QLabel(tr("Charset"))); box = new QComboBox(); hb->addWidget(box); pWA = new QWidgetAction(0); pWA->setDefaultWidget(wgt); subMenu->addAction(pWA); //must add action after the widget action is ready. is it a Qt bug? box->addItem(tr("Auto detect"), QString::fromLatin1("AutoDetect")); box->addItem(tr("System"), QString::fromLatin1("System")); foreach (const QByteArray& cs, QTextCodec::availableCodecs()) { box->addItem(QString::fromLatin1(cs), QString::fromLatin1(cs)); } connect(box, SIGNAL(activated(QString)), SLOT(setSubtitleCharset(QString))); mpSubtitle->setCodec(box->itemData(box->currentIndex()).toByteArray()); box->setToolTip(tr("Auto detect requires libchardet")); subMenu = new ClickableMenu(tr("Audio track")); mpMenu->addMenu(subMenu); mpAudioTrackMenu = subMenu; connect(subMenu, SIGNAL(triggered(QAction*)), SLOT(changeAudioTrack(QAction*))); initAudioTrackMenu(); subMenu = new ClickableMenu(tr("Channel")); mpMenu->addMenu(subMenu); mpChannelMenu = subMenu; connect(subMenu, SIGNAL(triggered(QAction*)), SLOT(changeChannel(QAction*))); subMenu->addAction(tr("As input"))->setData(AudioFormat::ChannelLayout_Unsupported); //will set to input in resampler if not supported. subMenu->addAction(tr("Stero"))->setData(AudioFormat::ChannelLayout_Stero); subMenu->addAction(tr("Mono (center)"))->setData(AudioFormat::ChannelLayout_Center); subMenu->addAction(tr("Left"))->setData(AudioFormat::ChannelLayout_Left); subMenu->addAction(tr("Right"))->setData(AudioFormat::ChannelLayout_Right); ag = new QActionGroup(subMenu); ag->setExclusive(true); foreach(QAction* action, subMenu->actions()) { ag->addAction(action); action->setCheckable(true); } subMenu = new QMenu(tr("Aspect ratio"), mpMenu); mpMenu->addMenu(subMenu); connect(subMenu, SIGNAL(triggered(QAction*)), SLOT(switchAspectRatio(QAction*))); mpARAction = subMenu->addAction(tr("Video")); mpARAction->setData(0); subMenu->addAction(tr("Window"))->setData(-1); subMenu->addAction(QString::fromLatin1("4:3"))->setData(4.0/3.0); subMenu->addAction(QString::fromLatin1("16:9"))->setData(16.0/9.0); subMenu->addAction(tr("Custom"))->setData(-2); foreach(QAction* action, subMenu->actions()) { action->setCheckable(true); } mpARAction->setChecked(true); subMenu = new ClickableMenu(tr("Color space")); mpMenu->addMenu(subMenu); mpVideoEQ = new VideoEQConfigPage(); connect(mpVideoEQ, SIGNAL(engineChanged()), SLOT(onVideoEQEngineChanged())); pWA = new QWidgetAction(0); pWA->setDefaultWidget(mpVideoEQ); subMenu->addAction(pWA); subMenu = new ClickableMenu(tr("Decoder")); mpMenu->addMenu(subMenu); mpDecoderConfigPage = new DecoderConfigPage(); pWA = new QWidgetAction(0); pWA->setDefaultWidget(mpDecoderConfigPage); subMenu->addAction(pWA); subMenu = new ClickableMenu(tr("Renderer")); mpMenu->addMenu(subMenu); connect(subMenu, SIGNAL(triggered(QAction*)), SLOT(changeVO(QAction*))); //TODO: AVOutput.name,detail(description). check whether it is available mpVOAction = subMenu->addAction(QString::fromLatin1("QPainter")); mpVOAction->setData(VideoRendererId_Widget); subMenu->addAction(QString::fromLatin1("OpenGLWidget"))->setData(VideoRendererId_OpenGLWidget); subMenu->addAction(QString::fromLatin1("GLWidget 2"))->setData(VideoRendererId_GLWidget2); subMenu->addAction(QString::fromLatin1("GLWidget"))->setData(VideoRendererId_GLWidget); subMenu->addAction(QString::fromLatin1("GDI+"))->setData(VideoRendererId_GDI); subMenu->addAction(QString::fromLatin1("Direct2D"))->setData(VideoRendererId_Direct2D); subMenu->addAction(QString::fromLatin1("XV"))->setData(VideoRendererId_XV); mVOActions = subMenu->actions(); foreach(QAction* action, subMenu->actions()) { action->setCheckable(true); } mpVOAction->setChecked(true); mainLayout->addLayout(mpPlayerLayout); mainLayout->addWidget(mpTimeSlider); mainLayout->addWidget(mpControl); QHBoxLayout *controlLayout = new QHBoxLayout(); controlLayout->setSpacing(0); controlLayout->setMargin(1); mpControl->setLayout(controlLayout); controlLayout->addWidget(mpCurrent); controlLayout->addWidget(mpTitle); QSpacerItem *space = new QSpacerItem(mpPlayPauseBtn->width(), mpPlayPauseBtn->height(), QSizePolicy::MinimumExpanding); controlLayout->addSpacerItem(space); controlLayout->addWidget(mpVolumeSlider); controlLayout->addWidget(mpVolumeBtn); controlLayout->addWidget(mpCaptureBtn); controlLayout->addWidget(mpPlayPauseBtn); controlLayout->addWidget(mpStopBtn); controlLayout->addWidget(mpBackwardBtn); controlLayout->addWidget(mpForwardBtn); controlLayout->addWidget(mpOpenBtn); controlLayout->addWidget(mpInfoBtn); controlLayout->addWidget(mpSpeed); //controlLayout->addWidget(mpSetupBtn); controlLayout->addWidget(mpMenuBtn); controlLayout->addWidget(mpEnd); connect(pSpeedBox, SIGNAL(valueChanged(double)), SLOT(onSpinBoxChanged(double))); connect(mpOpenBtn, SIGNAL(clicked()), SLOT(openFile())); connect(mpPlayPauseBtn, SIGNAL(clicked()), SLOT(togglePlayPause())); connect(mpInfoBtn, SIGNAL(clicked()), SLOT(showInfo())); //valueChanged can be triggered by non-mouse event //TODO: connect sliderMoved(int) to preview(int) connect(mpTimeSlider, SIGNAL(sliderPressed()), SLOT(seek())); connect(mpTimeSlider, SIGNAL(sliderReleased()), SLOT(seek())); connect(mpTimeSlider, SIGNAL(onLeave()), SLOT(onTimeSliderLeave())); connect(mpTimeSlider, SIGNAL(onHover(int,int)), SLOT(onTimeSliderHover(int,int))); QTimer::singleShot(0, this, SLOT(initPlayer())); } void MainWindow::changeChannel(QAction *action) { if (action == mpChannelAction) { action->toggle(); return; } AudioFormat::ChannelLayout cl = (AudioFormat::ChannelLayout)action->data().toInt(); AudioOutput *ao = mpPlayer ? mpPlayer->audio() : 0; //getAO()? if (!ao) { qWarning("No audio output!"); return; } mpChannelAction->setChecked(false); mpChannelAction = action; mpChannelAction->setChecked(true); if (!ao->close()) { qWarning("close audio failed"); return; } ao->audioFormat().setChannelLayout(cl); if (!ao->open()) { qWarning("open audio failed"); return; } } void MainWindow::changeAudioTrack(QAction *action) { int track = action->data().toInt(); if (mpAudioTrackAction == action && track >= 0) { // external action is always clickable action->toggle(); return; } if (track < 0) { QString f = QFileDialog::getOpenFileName(0, tr("Open an external audio track")); if (f.isEmpty()) { action->toggle(); return; } mpPlayer->setExternalAudio(f); } else { mpPlayer->setExternalAudio(QString()); if (!mpPlayer->setAudioStream(track)) { action->toggle(); return; } } if (mpAudioTrackAction) mpAudioTrackAction->setChecked(false); mpAudioTrackAction = action; mpAudioTrackAction->setChecked(true); if (mpStatisticsView && mpStatisticsView->isVisible()) mpStatisticsView->setStatistics(mpPlayer->statistics()); } void MainWindow::changeVO(QAction *action) { if (action == mpVOAction) { action->toggle(); //check state changes if clicked return; } VideoRendererId vid = (VideoRendererId)action->data().toInt(); VideoRenderer *vo = VideoRenderer::create(vid); if (vo && vo->isAvailable()) { setRenderer(vo); } else { action->toggle(); //check state changes if clicked QMessageBox::critical(0, QString::fromLatin1("QtAV"), tr("not availabe on your platform!")); return; } } void MainWindow::processPendingActions() { if (!mpTempRenderer) return; setRenderer(mpTempRenderer); mpTempRenderer = 0; if (mHasPendingPlay) { mHasPendingPlay = false; play(mFile); } } void MainWindow::setAudioBackends(const QStringList& backends) { mAudioBackends = backends; } void MainWindow::setRenderer(QtAV::VideoRenderer *renderer) { if (!mIsReady) { mpTempRenderer = renderer; return; } if (!renderer) return; mpOSD->uninstall(); mpSubtitle->uninstall(); renderer->widget()->setMouseTracking(true); //mouseMoveEvent without press. mpPlayer->setRenderer(renderer); QWidget *r = 0; if (mpRenderer) r = mpRenderer->widget(); //release old renderer and add new if (r) { mpPlayerLayout->removeWidget(r); if (r->testAttribute(Qt::WA_DeleteOnClose)) { r->close(); } else { r->close(); delete r; } r = 0; } mpRenderer = renderer; //setInSize? mpPlayerLayout->addWidget(renderer->widget()); if (mpVOAction) { mpVOAction->setChecked(false); } foreach (QAction *action, mVOActions) { if (action->data() == renderer->id()) { mpVOAction = action; break; } } mpVOAction->setChecked(true); mpTitle->setText(mpVOAction->text()); const VideoRendererId vid = mpPlayer->renderer()->id(); if (vid == VideoRendererId_GLWidget || vid == VideoRendererId_GLWidget2 || vid == VideoRendererId_OpenGLWidget ) { mpVideoEQ->setEngines(QVector() << VideoEQConfigPage::SWScale << VideoEQConfigPage::GLSL); mpVideoEQ->setEngine(VideoEQConfigPage::GLSL); mpPlayer->renderer()->forcePreferredPixelFormat(true); } else if (vid == VideoRendererId_XV) { mpVideoEQ->setEngines(QVector() << VideoEQConfigPage::XV); mpVideoEQ->setEngine(VideoEQConfigPage::XV); mpPlayer->renderer()->forcePreferredPixelFormat(true); } else { mpVideoEQ->setEngines(QVector() << VideoEQConfigPage::SWScale); mpVideoEQ->setEngine(VideoEQConfigPage::SWScale); mpPlayer->renderer()->forcePreferredPixelFormat(false); } onVideoEQEngineChanged(); mpOSD->installTo(mpRenderer); mpSubtitle->installTo(mpRenderer); } void MainWindow::play(const QString &name) { mFile = name; if (!mIsReady) { mHasPendingPlay = true; return; } mTitle = mFile; if (!mFile.contains(QLatin1String("://")) || mFile.startsWith(QLatin1String("file://"))) { mTitle = QFileInfo(mFile).fileName(); } setWindowTitle(mTitle); mpPlayer->stop(); //if no stop, in setPriority decoder will reopen mpPlayer->setFrameRate(Config::instance().forceFrameRate()); if (!mAudioBackends.isEmpty()) mpPlayer->audio()->setBackends(mAudioBackends); if (!mpRepeatEnableAction->isChecked()) mRepeateMax = 0; mpPlayer->setInterruptOnTimeout(Config::instance().abortOnTimeout()); mpPlayer->setInterruptTimeout(Config::instance().timeout()*1000.0); mpPlayer->setBufferMode(QtAV::BufferPackets); mpPlayer->setBufferValue(Config::instance().bufferValue()); mpPlayer->setRepeat(mRepeateMax); mpPlayer->setPriority(idsFromNames(Config::instance().decoderPriorityNames())); mpPlayer->setOptionsForAudioCodec(mpDecoderConfigPage->audioDecoderOptions()); mpPlayer->setOptionsForVideoCodec(mpDecoderConfigPage->videoDecoderOptions()); if (Config::instance().avformatOptionsEnabled()) mpPlayer->setOptionsForFormat(Config::instance().avformatOptions()); PlayListItem item; item.setUrl(mFile); item.setTitle(mTitle); item.setLastTime(0); mpHistory->remove(mFile); mpHistory->insertItemAt(item, 0); mpPlayer->play(name); } void MainWindow::play(const QUrl &url) { play(QUrl::fromPercentEncoding(url.toEncoded())); } void MainWindow::setVideoDecoderNames(const QStringList &vd) { QStringList vdnames; foreach (const QString& v, vd) { vdnames << v.toLower(); } QStringList vidp; QStringList vids = idsToNames(VideoDecoder::registered()); foreach (const QString& v, vids) { if (vdnames.contains(v.toLower())) { vidp.append(v); } } Config::instance().setDecoderPriorityNames(vidp); } void MainWindow::openFile() { QString file = QFileDialog::getOpenFileName(0, tr("Open a media file"), Config::instance().lastFile()); if (file.isEmpty()) return; Config::instance().setLastFile(file); play(file); } void MainWindow::togglePlayPause() { if (mpPlayer->isPlaying()) { qDebug("isPaused = %d", mpPlayer->isPaused()); mpPlayer->pause(!mpPlayer->isPaused()); } else { if (mFile.isEmpty()) return; if (!mpPlayer->isPlaying()) play(mFile); else mpPlayer->play(); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/pause.svg"))); } } void MainWindow::showNextOSD() { if (!mpOSD) return; mpOSD->useNextShowType(); } void MainWindow::onSpinBoxChanged(double v) { if (!mpPlayer) return; mpPlayer->setSpeed(v); } void MainWindow::onPaused(bool p) { if (p) { qDebug("start pausing..."); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/play.svg"))); } else { qDebug("stop pausing..."); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/pause.svg"))); } } void MainWindow::onStartPlay() { mpRenderer->setRegionOfInterest(QRectF()); mFile = mpPlayer->file(); //open from EventFilter's menu mTitle = mFile; if (!mFile.contains(QLatin1String("://")) || mFile.startsWith(QLatin1String("file://"))) mTitle = QFileInfo(mFile).fileName(); setWindowTitle(mTitle); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/pause.svg"))); mpTimeSlider->setMinimum(mpPlayer->mediaStartPosition()); mpTimeSlider->setMaximum(mpPlayer->mediaStopPosition()); mpTimeSlider->setValue(0); mpTimeSlider->setEnabled(mpPlayer->isSeekable()); mpEnd->setText(QTime(0, 0, 0).addMSecs(mpPlayer->mediaStopPosition()).toString(QString::fromLatin1("HH:mm:ss"))); setVolume(); mShowControl = 0; QTimer::singleShot(3000, this, SLOT(tryHideControlBar())); ScreenSaver::instance().disable(); initAudioTrackMenu(); mpRepeatA->setMinimumTime(QTime(0, 0, 0).addMSecs(mpPlayer->mediaStartPosition())); mpRepeatA->setMaximumTime(QTime(0, 0, 0).addMSecs(mpPlayer->mediaStopPosition())); mpRepeatB->setMinimumTime(QTime(0, 0, 0).addMSecs(mpPlayer->mediaStartPosition())); mpRepeatB->setMaximumTime(QTime(0, 0, 0).addMSecs(mpPlayer->mediaStopPosition())); mpRepeatA->setTime(QTime(0, 0, 0).addMSecs(mpPlayer->startPosition())); mpRepeatB->setTime(QTime(0, 0, 0).addMSecs(mpPlayer->stopPosition())); mCursorTimer = startTimer(3000); PlayListItem item = mpHistory->itemAt(0); item.setUrl(mFile); item.setTitle(mTitle); item.setDuration(mpPlayer->duration()); mpHistory->setItemAt(item, 0); updateChannelMenu(); if (mpStatisticsView && mpStatisticsView->isVisible()) mpStatisticsView->setStatistics(mpPlayer->statistics()); } void MainWindow::onStopPlay() { mpPlayer->setPriority(idsFromNames(Config::instance().decoderPriorityNames())); if (mpPlayer->currentRepeat() < mpPlayer->repeat()) return; // use shortcut to replay in EventFilter, the options will not be set, so set here mpPlayer->setFrameRate(Config::instance().forceFrameRate()); mpPlayer->setOptionsForAudioCodec(mpDecoderConfigPage->audioDecoderOptions()); mpPlayer->setOptionsForVideoCodec(mpDecoderConfigPage->videoDecoderOptions()); if (Config::instance().avformatOptionsEnabled()) mpPlayer->setOptionsForFormat(Config::instance().avformatOptions()); mpPlayPauseBtn->setIcon(QIcon(QString::fromLatin1(":/theme/dark/play.svg"))); mpTimeSlider->setValue(0); qDebug(">>>>>>>>>>>>>>disable slider"); mpTimeSlider->setDisabled(true); mpTimeSlider->setMinimum(0); mpTimeSlider->setMaximum(0); mpCurrent->setText(QString::fromLatin1("00:00:00")); mpEnd->setText(QString::fromLatin1("00:00:00")); tryShowControlBar(); ScreenSaver::instance().enable(); toggleRepeat(false); //mRepeateMax = 0; killTimer(mCursorTimer); unsetCursor(); if (m_preview) m_preview->setFile(QString()); } void MainWindow::onSpeedChange(qreal speed) { mpSpeed->setText(QString::fromLatin1("%1").arg(speed, 4, 'f', 2, QLatin1Char('0'))); } void MainWindow::seek() { mpPlayer->setSeekType(AccurateSeek); mpPlayer->seek((qint64)mpTimeSlider->value()); if (!m_preview || !Config::instance().previewEnabled()) return; m_preview->setTimestamp(mpTimeSlider->value()); m_preview->preview(); m_preview->setWindowFlags(m_preview->windowFlags() |Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint); m_preview->resize(Config::instance().previewWidth(), Config::instance().previewHeight()); m_preview->show(); } void MainWindow::showHideVolumeBar() { if (mpVolumeSlider->isHidden()) { mpVolumeSlider->show(); } else { mpVolumeSlider->hide(); } } void MainWindow::setVolume() { AudioOutput *ao = mpPlayer ? mpPlayer->audio() : 0; qreal v = qreal(mpVolumeSlider->value())*kVolumeInterval; if (ao) { if (qAbs(int(ao->volume()/kVolumeInterval) - mpVolumeSlider->value()) >= int(0.1/kVolumeInterval)) { ao->setVolume(v); } } mpVolumeSlider->setToolTip(QString::number(v)); mpVolumeBtn->setToolTip(QString::number(v)); } void MainWindow::closeEvent(QCloseEvent *e) { Q_UNUSED(e); if (mpPlayer) mpPlayer->stop(); qApp->quit(); } void MainWindow::resizeEvent(QResizeEvent *e) { Q_UNUSED(e); QWidget::resizeEvent(e); /* if (mpTitle) QLabelSetElideText(mpTitle, QFileInfo(mFile).fileName(), e->size().width()); */ } void MainWindow::timerEvent(QTimerEvent *e) { if (e->timerId() == mCursorTimer) { if (mpControl->isVisible()) return; setCursor(Qt::BlankCursor); } } void MainWindow::onPositionChange(qint64 pos) { if (mpPlayer->isSeekable()) mpTimeSlider->setValue(pos); mpCurrent->setText(QTime(0, 0, 0).addMSecs(pos).toString(QString::fromLatin1("HH:mm:ss"))); } void MainWindow::repeatAChanged(const QTime& t) { if (!mpPlayer) return; mpPlayer->setStartPosition(QTime(0, 0, 0).msecsTo(t)); } void MainWindow::repeatBChanged(const QTime& t) { if (!mpPlayer) return; // when this slot is called? even if only range is set? if (t <= mpRepeatA->time()) return; mpPlayer->setStopPosition(QTime(0, 0, 0).msecsTo(t)); } void MainWindow::keyPressEvent(QKeyEvent *e) { mControlOn = e->key() == Qt::Key_Control; } void MainWindow::keyReleaseEvent(QKeyEvent *e) { Q_UNUSED(e); mControlOn = false; } void MainWindow::mousePressEvent(QMouseEvent *e) { if (!mControlOn) return; mGlobalMouse = e->globalPos(); } void MainWindow::mouseMoveEvent(QMouseEvent *e) { unsetCursor(); if (e->pos().y() > height() - mpTimeSlider->height() - mpControl->height()) { if (mShowControl == 0) { mShowControl = 1; tryShowControlBar(); } } else { if (mShowControl == 1) { mShowControl = 0; QTimer::singleShot(3000, this, SLOT(tryHideControlBar())); } } if (mControlOn && e->button() == Qt::LeftButton) { if (!mpRenderer || !mpRenderer->widget()) return; QRectF roi = mpRenderer->realROI(); QPointF delta = e->pos() - mGlobalMouse; roi.moveLeft(-delta.x()); roi.moveTop(-delta.y()); mpRenderer->setRegionOfInterest(roi); } } void MainWindow::wheelEvent(QWheelEvent *e) { if (!mpRenderer || !mpRenderer->widget()) { return; } #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) qreal deg = e->angleDelta().y()/8; #else qreal deg = e->delta()/8; #endif //QT_VERSION #if WHEEL_SPEED if (!mControlOn) { qreal speed = mpPlayer->speed(); mpPlayer->setSpeed(qMax(0.01, speed + deg/15.0*0.02)); return; } #endif //WHEEL_SPEED QPointF p = mpRenderer->widget()->mapFrom(this, e->pos()); QPointF fp = mpRenderer->mapToFrame(p); if (fp.x() < 0) fp.setX(0); if (fp.y() < 0) fp.setY(0); if (fp.x() > mpRenderer->frameSize().width()) fp.setX(mpRenderer->frameSize().width()); if (fp.y() > mpRenderer->frameSize().height()) fp.setY(mpRenderer->frameSize().height()); QRectF viewport = QRectF(mpRenderer->mapToFrame(QPointF(0, 0)), mpRenderer->mapToFrame(QPointF(mpRenderer->rendererWidth(), mpRenderer->rendererHeight()))); //qDebug("vo: (%.1f, %.1f)=> frame: (%.1f, %.1f)", p.x(), p.y(), fp.x(), fp.y()); qreal zoom = 1.0 + deg*3.14/180.0; //qDebug("deg: %d, %d zoom: %.2f", e->angleDelta().x(), e->angleDelta().y(), zoom); QTransform m; m.translate(fp.x(), fp.y()); m.scale(1.0/zoom, 1.0/zoom); m.translate(-fp.x(), -fp.y()); QRectF r = m.mapRect(mpRenderer->realROI()); mpRenderer->setRegionOfInterest((r | m.mapRect(viewport))&QRectF(QPointF(0,0), mpRenderer->frameSize())); } void MainWindow::about() { QtAV::about(); } void MainWindow::help() { QString name = QString::fromLatin1("help-%1.html").arg(QLocale::system().name()); QFile f(qApp->applicationDirPath() + QString::fromLatin1("/") + name); if (!f.exists()) { f.setFileName(QString::fromLatin1(":/") + name); } if (!f.exists()) { f.setFileName(qApp->applicationDirPath() + QString::fromLatin1("/help.html")); } if (!f.exists()) { f.setFileName(QString::fromLatin1(":/help.html")); } if (!f.open(QIODevice::ReadOnly)) { qWarning("Failed to open help-%s.html and help.html: %s", qPrintable(QLocale::system().name()), qPrintable(f.errorString())); return; } QTextStream ts(&f); ts.setCodec("UTF-8"); QString text = ts.readAll(); QMessageBox::information(0, tr("Help"), text); } void MainWindow::openUrl() { QString url = QInputDialog::getText(0, tr("Open an url"), tr("Url")); if (url.isEmpty()) return; play(url); } void MainWindow::updateChannelMenu() { if (mpChannelAction) mpChannelAction->setChecked(false); AudioOutput *ao = mpPlayer ? mpPlayer->audio() : 0; //getAO()? if (!ao) { return; } AudioFormat::ChannelLayout cl = ao->audioFormat().channelLayout(); QList as = mpChannelMenu->actions(); foreach (QAction *action, as) { if (action->data().toInt() != (int)cl) continue; action->setChecked(true); mpChannelAction = action; break; } } void MainWindow::initAudioTrackMenu() { int track = -2; QAction *a = 0; QList as; int tracks = 0; if (!mpPlayer) { a = mpAudioTrackMenu->addAction(tr("External")); a->setData(-1); a->setCheckable(true); a->setChecked(false); as.push_back(a); mpAudioTrackAction = 0; goto end; } track = mpPlayer->currentAudioStream(); as = mpAudioTrackMenu->actions(); tracks = mpPlayer->audioStreamCount(); if (mpAudioTrackAction && tracks == as.size()-1 && mpAudioTrackAction->data().toInt() == track) return; while (tracks + 1 < as.size()) { a = as.takeLast(); mpAudioTrackMenu->removeAction(a); delete a; } if (as.isEmpty()) { a = mpAudioTrackMenu->addAction(tr("External")); a->setData(-1); a->setCheckable(true); a->setChecked(false); as.push_back(a); mpAudioTrackAction = 0; } while (tracks + 1 > as.size()) { a = mpAudioTrackMenu->addAction(QString::number(as.size()-1)); a->setData(as.size()-1); a->setCheckable(true); a->setChecked(false); as.push_back(a); } end: foreach(QAction *ac, as) { if (ac->data().toInt() == track && track >= 0) { if (mpPlayer && mpPlayer->externalAudio().isEmpty()) { qDebug("track found!!!!!"); mpAudioTrackAction = ac; ac->setChecked(true); } } else { ac->setChecked(false); } } if (mpPlayer && !mpPlayer->externalAudio().isEmpty()) { mpAudioTrackAction = as.first(); } if (mpAudioTrackAction) mpAudioTrackAction->setChecked(true); } void MainWindow::switchAspectRatio(QAction *action) { qreal r = action->data().toDouble(); if (action == mpARAction && r != -2) { action->toggle(); //check state changes if clicked return; } if (r == 0) { mpPlayer->renderer()->setOutAspectRatioMode(VideoRenderer::VideoAspectRatio); } else if (r == -1) { mpPlayer->renderer()->setOutAspectRatioMode(VideoRenderer::RendererAspectRatio); } else { if (r == -2) r = QInputDialog::getDouble(0, tr("Aspect ratio"), QString(), 1.0); mpPlayer->renderer()->setOutAspectRatioMode(VideoRenderer::CustomAspectRation); mpPlayer->renderer()->setOutAspectRatio(r); } mpARAction->setChecked(false); mpARAction = action; mpARAction->setChecked(true); } void MainWindow::toggleRepeat(bool r) { mpRepeatEnableAction->setChecked(r); mpRepeatAction->defaultWidget()->setEnabled(r); //why need defaultWidget? if (r) { mRepeateMax = mpRepeatBox->value(); } else { mRepeateMax = 0; } if (mpPlayer) { mpPlayer->setRepeat(mRepeateMax); } } void MainWindow::setRepeateMax(int m) { mRepeateMax = m; if (mpPlayer) { mpPlayer->setRepeat(m); } } void MainWindow::playOnlineVideo(QAction *action) { mTitle = action->text(); play(action->data().toString()); } void MainWindow::onTVMenuClick() { static TVView *tvv = new TVView; tvv->show(); connect(tvv, SIGNAL(clicked(QString,QString)), SLOT(onPlayListClick(QString,QString))); tvv->setMaximumHeight(qApp->desktop()->height()); tvv->setMinimumHeight(tvv->width()*2); } void MainWindow::onPlayListClick(const QString &key, const QString &value) { mTitle = key; play(value); } void MainWindow::tryHideControlBar() { if (mShowControl > 0) { return; } if (mpControl->isHidden() && mpTimeSlider->isHidden()) return; mpControl->hide(); mpTimeSlider->hide(); workaroundRendererSize(); } void MainWindow::tryShowControlBar() { unsetCursor(); if (mpTimeSlider && mpTimeSlider->isHidden()) mpTimeSlider->show(); if (mpControl && mpControl->isHidden()) mpControl->show(); } void MainWindow::showInfo() { if (!mpStatisticsView) mpStatisticsView = new StatisticsView(); if (mpPlayer) mpStatisticsView->setStatistics(mpPlayer->statistics()); mpStatisticsView->show(); } void MainWindow::onTimeSliderHover(int pos, int value) { QPoint gpos = mapToGlobal(mpTimeSlider->pos() + QPoint(pos, 0)); QToolTip::showText(gpos, QTime(0, 0, 0).addMSecs(value).toString(QString::fromLatin1("HH:mm:ss"))); if (!Config::instance().previewEnabled()) return; if (!m_preview) m_preview = new VideoPreviewWidget(); m_preview->setFile(mpPlayer->file()); m_preview->setTimestamp(value); m_preview->preview(); const int w = Config::instance().previewWidth(); const int h = Config::instance().previewHeight(); m_preview->setWindowFlags(m_preview->windowFlags() |Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint); m_preview->resize(w, h); m_preview->move(gpos - QPoint(w/2, h)); m_preview->show(); } void MainWindow::onTimeSliderLeave() { if (m_preview && m_preview->isVisible()) m_preview->hide(); } void MainWindow::handleError(const AVError &e) { QMessageBox::warning(0, tr("Player error"), e.string()); } void MainWindow::onMediaStatusChanged() { QString status; AVPlayer *player = qobject_cast(sender()); switch (player->mediaStatus()) { case NoMedia: status = tr("No media"); break; case InvalidMedia: status = tr("Invalid meida"); break; case BufferingMedia: status = tr("Buffering..."); break; case BufferedMedia: status = tr("Buffered"); break; case LoadingMedia: status = tr("Loading..."); break; case LoadedMedia: status = tr("Loaded"); break; case StalledMedia: status = tr("Stalled"); break; default: status = QString(); onStopPlay(); break; } qDebug() << "status changed " << status; setWindowTitle(status + QString::fromLatin1(" ") + mTitle); } void MainWindow::onBufferProgress(qreal percent) { setWindowTitle(QString::fromLatin1("Buffering... %1% ").arg(percent*100.0, 0, 'f', 1) + mTitle); } void MainWindow::onVideoEQEngineChanged() { VideoRenderer *vo = mpPlayer->renderer(); VideoEQConfigPage::Engine e = mpVideoEQ->engine(); if (e == VideoEQConfigPage::SWScale) { vo->forcePreferredPixelFormat(true); vo->setPreferredPixelFormat(VideoFormat::Format_RGB32); } else { vo->forcePreferredPixelFormat(false); } onBrightnessChanged(mpVideoEQ->brightness()*100.0); onContrastChanged(mpVideoEQ->contrast()*100.0); onHueChanged(mpVideoEQ->hue()*100.0); onSaturationChanged(mpVideoEQ->saturation()*100.0); } void MainWindow::onBrightnessChanged(int b) { VideoRenderer *vo = mpPlayer->renderer(); if (mpVideoEQ->engine() != VideoEQConfigPage::SWScale && vo->setBrightness(mpVideoEQ->brightness())) { mpPlayer->setBrightness(0); } else { vo->setBrightness(0); mpPlayer->setBrightness(b); } } void MainWindow::onContrastChanged(int c) { VideoRenderer *vo = mpPlayer->renderer(); if (mpVideoEQ->engine() != VideoEQConfigPage::SWScale && vo->setContrast(mpVideoEQ->contrast())) { mpPlayer->setContrast(0); } else { vo->setContrast(0); mpPlayer->setContrast(c); } } void MainWindow::onHueChanged(int h) { VideoRenderer *vo = mpPlayer->renderer(); if (mpVideoEQ->engine() != VideoEQConfigPage::SWScale && vo->setHue(mpVideoEQ->hue())) { mpPlayer->setHue(0); } else { vo->setHue(0); mpPlayer->setHue(h); } } void MainWindow::onSaturationChanged(int s) { VideoRenderer *vo = mpPlayer->renderer(); if (mpVideoEQ->engine() != VideoEQConfigPage::SWScale && vo->setSaturation(mpVideoEQ->saturation())) { mpPlayer->setSaturation(0); } else { vo->setSaturation(0); mpPlayer->setSaturation(s); } } void MainWindow::onCaptureConfigChanged() { mpPlayer->videoCapture()->setCaptureDir(Config::instance().captureDir()); mpPlayer->videoCapture()->setQuality(Config::instance().captureQuality()); if (Config::instance().captureFormat().toLower() == QLatin1String("original")) { mpPlayer->videoCapture()->setOriginalFormat(true); } else { mpPlayer->videoCapture()->setOriginalFormat(false); mpPlayer->videoCapture()->setSaveFormat(Config::instance().captureFormat()); } mpCaptureBtn->setToolTip(QString::fromLatin1("%1\n%2: %3\n%4: %5") .arg(tr("Capture video frame")) .arg(tr("Save to")) .arg(mpPlayer->videoCapture()->captureDir()) .arg(tr("Format")) .arg(Config::instance().captureFormat())); } void MainWindow::onAVFilterVideoConfigChanged() { if (Config::instance().avfilterVideoEnable()) { if (!mpVideoFilter) { mpVideoFilter = new LibAVFilterVideo(this); } mpVideoFilter->setEnabled(true); mpPlayer->installFilter(mpVideoFilter); mpVideoFilter->setOptions(Config::instance().avfilterVideoOptions()); } else { if (mpVideoFilter) { mpVideoFilter->setEnabled(false); } mpPlayer->uninstallFilter(mpVideoFilter); } } void MainWindow::onAVFilterAudioConfigChanged() { if (Config::instance().avfilterAudioEnable()) { if (!mpAudioFilter) { mpAudioFilter = new LibAVFilterAudio(this); } mpAudioFilter->setEnabled(true); mpPlayer->installFilter(mpAudioFilter); mpAudioFilter->setOptions(Config::instance().avfilterAudioOptions()); } else { if (mpAudioFilter) { mpAudioFilter->setEnabled(false); } mpPlayer->uninstallFilter(mpAudioFilter); } } void MainWindow::donate() { //QDesktopServices::openUrl(QUrl("https://sourceforge.net/p/qtav/wiki/Donate%20%E6%8D%90%E8%B5%A0/")); QDesktopServices::openUrl(QUrl(QString::fromLatin1("http://www.qtav.org/donate.html"))); } void MainWindow::onBufferValueChanged() { if (!mpPlayer) return; mpPlayer->setBufferValue(Config::instance().bufferValue()); } void MainWindow::onAbortOnTimeoutChanged() { if (!mpPlayer) return; mpPlayer->setInterruptOnTimeout(Config::instance().abortOnTimeout()); } void MainWindow::setup() { ConfigDialog::display(); } void MainWindow::handleFullscreenChange() { workaroundRendererSize(); // workaround renderer display size for ubuntu tryShowControlBar(); QTimer::singleShot(3000, this, SLOT(tryHideControlBar())); } void MainWindow::toggoleSubtitleEnabled(bool value) { mpSubtitle->setEnabled(value); } void MainWindow::toggleSubtitleAutoLoad(bool value) { mpSubtitle->setAutoLoad(value); } void MainWindow::openSubtitle() { QString file = QFileDialog::getOpenFileName(0, tr("Open a subtitle file")); if (file.isEmpty()) return; mpSubtitle->setFile(file); } void MainWindow::setSubtitleCharset(const QString &charSet) { Q_UNUSED(charSet); QComboBox *box = qobject_cast(sender()); if (!box) return; mpSubtitle->setCodec(box->itemData(box->currentIndex()).toByteArray()); } void MainWindow::setSubtitleEngine(const QString &value) { Q_UNUSED(value) QComboBox *box = qobject_cast(sender()); if (!box) return; mpSubtitle->setEngines(QStringList() << box->itemData(box->currentIndex()).toString()); } void MainWindow::changeClockType(QAction *action) { action->setChecked(true); int value = action->data().toInt(); if (value < 0) { mpPlayer->masterClock()->setClockAuto(true); // TODO: guess clock type return; } mpPlayer->masterClock()->setClockAuto(false); mpPlayer->masterClock()->setClockType(AVClock::ClockType(value)); } void MainWindow::syncVolumeUi(qreal value) { const int v(value/kVolumeInterval); if (mpVolumeSlider->value() == v) return; mpVolumeSlider->setValue(v); } void MainWindow::workaroundRendererSize() { if (!mpRenderer) return; QSize s = rect().size(); //resize(QSize(s.width()-1, s.height()-1)); //resize(s); //window resize to fullscreen size will create another fullScreenChange event mpRenderer->widget()->resize(QSize(s.width()+1, s.height()+1)); mpRenderer->widget()->resize(s); }