File indexing completed on 2024-12-22 04:40:20
0001 /* 0002 SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar> 0003 SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "videoplayer.h" 0009 #include "scconfig.h" 0010 0011 #include "videoplayer/backend/glrenderer.h" 0012 0013 #include <math.h> 0014 0015 #include <QTimer> 0016 #include <QFileInfo> 0017 #include <QApplication> 0018 #include <QEvent> 0019 0020 #include <QDebug> 0021 0022 #include <KLocalizedString> 0023 0024 #define VOLUME_MULTIPLIER (double(qMax(1, SCConfig::volumeAmplification())) / 3.) 0025 0026 using namespace SubtitleComposer; 0027 0028 0029 VideoPlayer::VideoPlayer() 0030 : m_player(new FFPlayer(this)), 0031 m_videoWidget(nullptr), 0032 m_filePath(), 0033 m_state(Initialized), 0034 m_duration(-1.0), 0035 m_fps(-1.0), 0036 m_playSpeed(.0), 0037 m_textStreams(), 0038 m_activeAudioStream(-2), 0039 m_audioStreams(), 0040 m_muted(false), 0041 m_volume(100.0) 0042 { 0043 m_player->renderer()->setOverlay(&m_subOverlay); 0044 0045 setupNotifications(); 0046 } 0047 0048 VideoPlayer::~VideoPlayer() 0049 { 0050 } 0051 0052 VideoPlayer * 0053 VideoPlayer::instance() 0054 { 0055 static VideoPlayer *player = nullptr; 0056 if(!player) 0057 player = new VideoPlayer(); 0058 return player; 0059 } 0060 0061 bool 0062 VideoPlayer::init(QWidget *videoContainer) 0063 { 0064 if(!m_videoWidget) { 0065 m_videoWidget = new VideoWidget(videoContainer); 0066 m_videoWidget->setVideoLayer(m_player->renderer()); 0067 0068 connect(m_videoWidget, &VideoWidget::doubleClicked, this, &VideoPlayer::doubleClicked); 0069 connect(m_videoWidget, &VideoWidget::rightClicked, this, &VideoPlayer::rightClicked); 0070 connect(m_videoWidget, &VideoWidget::leftClicked, this, &VideoPlayer::leftClicked); 0071 connect(m_videoWidget, &VideoWidget::wheelUp, this, &VideoPlayer::wheelUp); 0072 connect(m_videoWidget, &VideoWidget::wheelDown, this, &VideoPlayer::wheelDown); 0073 } else { 0074 m_videoWidget->setParent(videoContainer); 0075 } 0076 reset(); 0077 0078 return true; 0079 } 0080 0081 void 0082 VideoPlayer::reset() 0083 { 0084 m_filePath.clear(); 0085 0086 m_duration = -1.0; 0087 m_fps = -1.0; 0088 0089 m_activeAudioStream = -2; 0090 m_textStreams.clear(); 0091 m_audioStreams.clear(); 0092 0093 m_state = Initialized; 0094 0095 if(m_videoWidget) 0096 m_videoWidget->videoLayer()->hide(); 0097 } 0098 0099 bool 0100 VideoPlayer::playOnLoad() 0101 { 0102 const QWidget *topLevel = m_videoWidget->topLevelWidget(); 0103 const QWidget *dockWaveform = topLevel->findChild<QWidget *>(QStringLiteral("waveform_dock")); 0104 const QWidget *dockVideo = topLevel->findChild<QWidget *>(QStringLiteral("player_dock")); 0105 return SCConfig::videoAutoPlay() && (dockVideo->isVisible() || dockWaveform->isVisible()); 0106 } 0107 0108 bool 0109 VideoPlayer::openFile(const QString &filePath) 0110 { 0111 Q_ASSERT(m_state == Initialized || m_state == Stopped); 0112 0113 QFileInfo fileInfo(filePath); 0114 if(!fileInfo.exists() || !fileInfo.isFile() || !fileInfo.isReadable()) { 0115 emit fileOpenError(filePath, i18n("File does not exist.")); // operation will never succeed 0116 return false; 0117 } 0118 0119 m_filePath = filePath; 0120 m_state = Opening; 0121 0122 if(!m_player->open(fileInfo.absoluteFilePath().toUtf8())) 0123 return false; 0124 0125 if(m_player->paused() == playOnLoad()) 0126 m_player->pauseToggle(); 0127 0128 return true; 0129 } 0130 0131 void 0132 VideoPlayer::closeFile() 0133 { 0134 if(m_state < Opening) 0135 return; 0136 m_player->close(); 0137 reset(); 0138 emit fileClosed(); 0139 } 0140 0141 void 0142 VideoPlayer::play() 0143 { 0144 if(m_state <= Opening || m_state == Playing) 0145 return; 0146 if(m_state < Playing) 0147 openFile(m_filePath); 0148 if(m_state == Paused) 0149 m_player->pauseToggle(); 0150 } 0151 0152 void 0153 VideoPlayer::pause() 0154 { 0155 if(m_state <= Opening || m_state == Paused) 0156 return; 0157 m_player->pauseToggle(); 0158 } 0159 0160 void 0161 VideoPlayer::togglePlayPaused() 0162 { 0163 if(m_state == Playing) 0164 pause(); 0165 else if(m_state > Opening) 0166 play(); 0167 } 0168 0169 bool 0170 VideoPlayer::seek(double seconds) 0171 { 0172 if(m_state <= Stopped) 0173 return false; 0174 m_player->seek(qBound(0., seconds, m_duration)); 0175 return true; 0176 } 0177 0178 bool 0179 VideoPlayer::step(int frameOffset) 0180 { 0181 if(m_state <= Stopped) 0182 return false; 0183 m_player->stepFrame(frameOffset); 0184 return true; 0185 } 0186 0187 bool 0188 VideoPlayer::stop() 0189 { 0190 if(m_state <= Stopped) 0191 return false; 0192 m_player->close(); 0193 return true; 0194 } 0195 0196 bool 0197 VideoPlayer::selectAudioStream(int streamIndex) 0198 { 0199 if(m_state <= VideoPlayer::Opening || streamIndex < 0 || streamIndex >= m_audioStreams.size()) 0200 return false; 0201 0202 if(m_activeAudioStream != streamIndex) { 0203 m_activeAudioStream = streamIndex; 0204 m_player->activeAudioStream(streamIndex); 0205 emit activeAudioStreamChanged(streamIndex); 0206 } 0207 return true; 0208 } 0209 0210 void 0211 VideoPlayer::playSpeed(double newRate) 0212 { 0213 if(m_state <= Opening || newRate < .05 || newRate > 8.) 0214 return; 0215 0216 m_player->setSpeed(newRate); 0217 } 0218 0219 void 0220 VideoPlayer::increaseVolume(double amount) 0221 { 0222 setVolume(m_volume + amount); 0223 setMuted(false); 0224 } 0225 0226 void 0227 VideoPlayer::decreaseVolume(double amount) 0228 { 0229 setVolume(m_volume - amount); 0230 } 0231 0232 void 0233 VideoPlayer::setVolume(double volume) 0234 { 0235 volume = qBound(0., volume, 100.); 0236 m_player->setVolume(VOLUME_MULTIPLIER * volume / 100.); 0237 0238 if(m_volume != volume) 0239 emit volumeChanged(m_volume = volume); 0240 } 0241 0242 void 0243 VideoPlayer::setMuted(bool muted) 0244 { 0245 m_player->setMuted(muted); 0246 0247 if(m_muted == muted) 0248 return; 0249 0250 m_muted = muted; 0251 0252 emit muteChanged(m_muted); 0253 } 0254 0255 void 0256 VideoPlayer::setupNotifications() 0257 { 0258 connect(m_player, &FFPlayer::mediaLoaded, this, [this](){ 0259 m_player->renderer()->reset(); 0260 emit fileOpened(m_filePath); 0261 m_fps = m_player->videoFPS(); 0262 emit fpsChanged(m_fps); 0263 m_videoWidget->videoLayer()->show(); 0264 }); 0265 connect(m_player, &FFPlayer::stateChanged, this, [this](FFPlayer::State ffs){ 0266 if(m_state == Initialized) // video file is closed don't notify play/pause/stop 0267 return; 0268 static const QMap<FFPlayer::State, State> stateMap 0269 {{ FFPlayer::Stopped, Stopped }, { FFPlayer::Playing, Playing }, { FFPlayer::Paused, Paused }}; 0270 const State state = stateMap[ffs]; 0271 if(m_state != state) switch(m_state = state) { 0272 case Stopped: emit stopped(); break; 0273 case Playing: emit playing(); break; 0274 case Paused: emit paused(); break; 0275 default: break; // not possible 0276 } 0277 }); 0278 connect(m_player->renderer(), &GLRenderer::resolutionChanged, this, [this](){ 0279 m_videoWidget->setVideoResolution(m_player->videoWidth(), m_player->videoHeight(), m_player->videoSAR()); 0280 m_videoWidget->videoLayer()->show(); 0281 }); 0282 0283 connect(m_player, &FFPlayer::positionChanged, this, &VideoPlayer::positionChanged); 0284 0285 connect(m_player, &FFPlayer::durationChanged, this, [this](double dur){ 0286 if(m_duration != dur) emit durationChanged(m_duration = dur); 0287 }); 0288 connect(m_player, &FFPlayer::speedChanged, this, [this](double speed){ 0289 if(m_playSpeed != speed) emit playSpeedChanged(m_playSpeed = speed); 0290 }); 0291 0292 connect(m_player, &FFPlayer::volumeChanged, this, [this](double volume){ 0293 if(m_volume != (volume = volume * 100. / VOLUME_MULTIPLIER)) { 0294 m_volume = volume; 0295 if(!m_muted) emit volumeChanged(m_volume); 0296 } 0297 }); 0298 connect(m_player, &FFPlayer::muteChanged, this, [this](bool muted){ 0299 if(m_muted != muted) emit muteChanged(m_muted = muted); 0300 }); 0301 0302 //connect(m_player, &FFPlayer::videoStreamsChanged, this, [this](const QStringList &streams){}); 0303 connect(m_player, &FFPlayer::audioStreamsChanged, this, [this](const QStringList &streams){ 0304 if(m_activeAudioStream >= 0) 0305 m_player->activeAudioStream(m_activeAudioStream); 0306 emit audioStreamsChanged(m_audioStreams = streams); 0307 emit activeAudioStreamChanged(m_activeAudioStream = m_player->activeAudioStream()); 0308 }); 0309 connect(m_player, &FFPlayer::subtitleStreamsChanged, this, [this](const QStringList &streams){ 0310 emit textStreamsChanged(m_textStreams = streams); 0311 }); 0312 }