mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-30 03:55:40 +00:00
Greatly simplified the video controls code.
Also fixed a cosmetic issue with carousel fade transitions.
This commit is contained in:
parent
ee1a0f7cd3
commit
c4eb1b8b97
|
@ -1196,7 +1196,7 @@ void FileData::launchGame()
|
|||
// This blocks the video player, stops the scrolling of game names and descriptions and
|
||||
// keeps the screensaver from getting activated.
|
||||
if (runInBackground)
|
||||
window->setLaunchedGame();
|
||||
window->setLaunchedGame(true);
|
||||
// Normalize deltaTime so that the screensaver does not start immediately
|
||||
// when returning from the game.
|
||||
window->normalizeNextUpdate();
|
||||
|
|
|
@ -43,9 +43,6 @@ bool MediaViewer::startMediaViewer(FileData* game)
|
|||
|
||||
initiateViewer();
|
||||
|
||||
if (mHasVideo)
|
||||
ViewController::getInstance()->onPauseVideo();
|
||||
|
||||
if (mHasVideo || mHasImages)
|
||||
return true;
|
||||
else
|
||||
|
@ -55,7 +52,7 @@ bool MediaViewer::startMediaViewer(FileData* game)
|
|||
void MediaViewer::stopMediaViewer()
|
||||
{
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||
ViewController::getInstance()->onStopVideo();
|
||||
ViewController::getInstance()->stopViewVideos();
|
||||
|
||||
if (mVideo) {
|
||||
delete mVideo;
|
||||
|
@ -257,10 +254,9 @@ void MediaViewer::playVideo()
|
|||
return;
|
||||
|
||||
mDisplayingImage = false;
|
||||
ViewController::getInstance()->onStopVideo();
|
||||
ViewController::getInstance()->pauseViewVideos();
|
||||
|
||||
mVideo = new VideoFFmpegComponent;
|
||||
mVideo->topWindow(true);
|
||||
mVideo->setOrigin(0.5f, 0.5f);
|
||||
mVideo->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
|
||||
|
||||
|
@ -271,7 +267,7 @@ void MediaViewer::playVideo()
|
|||
|
||||
mVideo->setVideo(mVideoFile);
|
||||
mVideo->setMediaViewerMode(true);
|
||||
mVideo->onShow();
|
||||
mVideo->startVideoPlayer();
|
||||
}
|
||||
|
||||
void MediaViewer::showImage(int index)
|
||||
|
|
|
@ -59,6 +59,8 @@ Screensaver::~Screensaver()
|
|||
|
||||
void Screensaver::startScreensaver(bool generateMediaList)
|
||||
{
|
||||
ViewController::getInstance()->pauseViewVideos();
|
||||
|
||||
std::string path = "";
|
||||
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
|
||||
mHasMediaFiles = false;
|
||||
|
@ -157,7 +159,6 @@ void Screensaver::startScreensaver(bool generateMediaList)
|
|||
generateOverlayInfo();
|
||||
|
||||
mVideoScreensaver = new VideoFFmpegComponent;
|
||||
mVideoScreensaver->topWindow(true);
|
||||
mVideoScreensaver->setOrigin(0.5f, 0.5f);
|
||||
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
||||
Renderer::getScreenHeight() / 2.0f);
|
||||
|
@ -171,7 +172,7 @@ void Screensaver::startScreensaver(bool generateMediaList)
|
|||
|
||||
mVideoScreensaver->setVideo(path);
|
||||
mVideoScreensaver->setScreensaverMode(true);
|
||||
mVideoScreensaver->onShow();
|
||||
mVideoScreensaver->startVideoPlayer();
|
||||
mTimer = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -197,6 +198,8 @@ void Screensaver::stopScreensaver()
|
|||
|
||||
if (mGameOverlay)
|
||||
mGameOverlay.reset();
|
||||
|
||||
ViewController::getInstance()->startViewVideos();
|
||||
}
|
||||
|
||||
void Screensaver::nextGame()
|
||||
|
@ -215,6 +218,7 @@ void Screensaver::launchGame()
|
|||
ViewController::getInstance()->getGamelistView(mCurrentGame->getSystem()).get();
|
||||
view->setCursor(mCurrentGame);
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
ViewController::getInstance()->pauseViewVideos();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,8 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
|||
// the menu has been closed.
|
||||
ViewController::getInstance()->stopScrolling();
|
||||
|
||||
ViewController::getInstance()->startViewVideos();
|
||||
|
||||
if (mFiltersChanged) {
|
||||
if (!mCustomCollectionSystem) {
|
||||
ViewController::getInstance()->reloadGamelistView(mSystem);
|
||||
|
|
|
@ -87,6 +87,8 @@ GuiMenu::~GuiMenu()
|
|||
// was openened. Without this, the scrolling would run until manually stopped after
|
||||
// the menu has been closed.
|
||||
ViewController::getInstance()->stopScrolling();
|
||||
|
||||
ViewController::getInstance()->startViewVideos();
|
||||
}
|
||||
|
||||
void GuiMenu::openScraperOptions()
|
||||
|
|
|
@ -514,7 +514,6 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
|
||||
buttons.push_back(std::make_shared<ButtonComponent>("SAVE", "save metadata", [&] {
|
||||
save();
|
||||
ViewController::getInstance()->onPauseVideo();
|
||||
delete this;
|
||||
}));
|
||||
buttons.push_back(
|
||||
|
@ -841,7 +840,6 @@ void GuiMetaDataEd::close()
|
|||
CollectionSystemsManager::getInstance()->refreshCollectionSystems(mScraperParams.game);
|
||||
mWindow->invalidateCachedBackground();
|
||||
}
|
||||
ViewController::getInstance()->onPauseVideo();
|
||||
delete this;
|
||||
};
|
||||
|
||||
|
|
|
@ -175,7 +175,6 @@ GuiScraperMulti::~GuiScraperMulti()
|
|||
(*it)->sortSystem();
|
||||
}
|
||||
}
|
||||
ViewController::getInstance()->onPauseVideo();
|
||||
}
|
||||
|
||||
void GuiScraperMulti::onSizeChanged()
|
||||
|
|
|
@ -261,7 +261,7 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
scrapeFiles.push_back(mediaFileInfo);
|
||||
#if defined(_WIN64)
|
||||
// Required due to the idiotic file locking that exists on this operating system.
|
||||
ViewController::getInstance()->onStopVideo();
|
||||
ViewController::getInstance()->stopVideo();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
if (config->isMappedTo("a", input)) {
|
||||
FileData* cursor = getCursor();
|
||||
if (cursor->getType() == GAME) {
|
||||
onPauseVideo();
|
||||
pauseViewVideos();
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
stopListScrolling();
|
||||
launch(cursor);
|
||||
|
@ -131,7 +131,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
}
|
||||
else {
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(BACKSOUND);
|
||||
onPauseVideo();
|
||||
muteViewVideos();
|
||||
onFocusLost();
|
||||
stopListScrolling();
|
||||
SystemData* systemToView = getCursor()->getSystem();
|
||||
|
@ -175,7 +175,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
else if (config->isMappedLike(getQuickSystemSelectRightButton(), input)) {
|
||||
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
||||
SystemData::sSystemVector.size() > 1) {
|
||||
onPauseVideo();
|
||||
muteViewVideos();
|
||||
onFocusLost();
|
||||
stopListScrolling();
|
||||
ViewController::getInstance()->goToNextGamelist();
|
||||
|
@ -185,7 +185,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
else if (config->isMappedLike(getQuickSystemSelectLeftButton(), input)) {
|
||||
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
||||
SystemData::sSystemVector.size() > 1) {
|
||||
onPauseVideo();
|
||||
muteViewVideos();
|
||||
onFocusLost();
|
||||
stopListScrolling();
|
||||
ViewController::getInstance()->goToPrevGamelist();
|
||||
|
@ -457,6 +457,7 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
config->isMappedTo("back", input) && input.value) {
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
stopListScrolling();
|
||||
pauseViewVideos();
|
||||
mWindow->pushGui(new GuiGamelistOptions(this->mRoot->getSystem()));
|
||||
return true;
|
||||
}
|
||||
|
@ -621,7 +622,7 @@ void GamelistBase::generateFirstLetterIndex(const std::vector<FileData*>& files)
|
|||
void GamelistBase::generateGamelistInfo(FileData* cursor, FileData* firstEntry)
|
||||
{
|
||||
// Generate data needed for the gamelistInfo field, which is displayed from the
|
||||
// gamelist interfaces (Detailed/Video/Grid).
|
||||
// gamelist interfaces.
|
||||
mIsFiltered = false;
|
||||
mIsFolder = false;
|
||||
FileData* rootFolder {firstEntry->getSystem()->getRootFolder()};
|
||||
|
@ -704,7 +705,7 @@ void GamelistBase::removeMedia(FileData* game)
|
|||
std::string path;
|
||||
|
||||
// Stop the video player, especially important on Windows as the file would otherwise be locked.
|
||||
onStopVideo();
|
||||
stopViewVideos();
|
||||
|
||||
// If there are no media files left in the directory after the deletion, then remove
|
||||
// the directory too. Remove any empty parent directories as well.
|
||||
|
|
|
@ -366,6 +366,12 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
|
||||
bool fadingOut = false;
|
||||
if (file == nullptr) {
|
||||
if (mViewStyle == ViewController::VIDEO) {
|
||||
mVideoComponents.front()->stopVideoPlayer();
|
||||
mVideoComponents.front()->setVideo("");
|
||||
if (!mVideoComponents.front()->hasStartDelay())
|
||||
mVideoComponents.front()->setImage("");
|
||||
}
|
||||
mVideoPlaying = false;
|
||||
fadingOut = true;
|
||||
}
|
||||
|
@ -383,15 +389,12 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
mImageComponents[LegacyImage::MD_MARQUEE]->setImage(mRandomGame->getMarqueePath());
|
||||
if (mViewStyle == ViewController::VIDEO) {
|
||||
mVideoComponents.front()->setImage(mRandomGame->getImagePath());
|
||||
// Always stop the video before setting a new video as it will otherwise
|
||||
// continue to play if it has the same path (i.e. it is the same physical
|
||||
// video file) as the previously set video. That may happen when entering a
|
||||
// folder with the same name as the first game file inside, or as in this
|
||||
// case, when entering a custom collection.
|
||||
mVideoComponents.front()->onHide();
|
||||
mVideoComponents.front()->stopVideoPlayer();
|
||||
|
||||
if (!mVideoComponents.front()->setVideo(mRandomGame->getVideoPath()))
|
||||
mVideoComponents.front()->setDefaultVideo();
|
||||
|
||||
mVideoComponents.front()->startVideoPlayer();
|
||||
}
|
||||
else {
|
||||
mImageComponents[LegacyImage::MD_IMAGE]->setImage(mRandomGame->getImagePath());
|
||||
|
@ -413,10 +416,12 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
mImageComponents[LegacyImage::MD_MARQUEE]->setImage(file->getMarqueePath());
|
||||
if (mViewStyle == ViewController::VIDEO) {
|
||||
mVideoComponents.front()->setImage(file->getImagePath());
|
||||
mVideoComponents.front()->onHide();
|
||||
mVideoComponents.front()->stopVideoPlayer();
|
||||
|
||||
if (!mVideoComponents.front()->setVideo(file->getVideoPath()))
|
||||
mVideoComponents.front()->setDefaultVideo();
|
||||
|
||||
mVideoComponents.front()->startVideoPlayer();
|
||||
}
|
||||
else {
|
||||
mImageComponents[LegacyImage::MD_IMAGE]->setImage(file->getImagePath());
|
||||
|
@ -550,6 +555,8 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
comps.emplace_back(mImageComponents[LegacyImage::MD_THUMBNAIL].get());
|
||||
comps.emplace_back(mImageComponents[LegacyImage::MD_MARQUEE].get());
|
||||
comps.emplace_back(mImageComponents[LegacyImage::MD_IMAGE].get());
|
||||
if (mVideoComponents.size() > 0)
|
||||
comps.emplace_back(mVideoComponents.front().get());
|
||||
comps.push_back(mBadgeComponents.front().get());
|
||||
comps.push_back(mRatingComponents.front().get());
|
||||
|
||||
|
@ -576,12 +583,6 @@ void GamelistView::legacyUpdate(int deltaTime)
|
|||
mImageComponents[LegacyImage::MD_IMAGE]->finishAnimation(0);
|
||||
|
||||
if (mViewStyle == ViewController::VIDEO) {
|
||||
if (!mVideoPlaying)
|
||||
mVideoComponents.front()->onHide();
|
||||
else if (mVideoPlaying && !mVideoComponents.front()->isVideoPaused() &&
|
||||
!mWindow->isScreensaverActive())
|
||||
mVideoComponents.front()->onShow();
|
||||
|
||||
if (ViewController::getInstance()->getGameLaunchTriggered() &&
|
||||
mVideoComponents.front()->isAnimationPlaying(0))
|
||||
mVideoComponents.front()->finishAnimation(0);
|
||||
|
|
|
@ -204,23 +204,6 @@ void GamelistView::update(int deltaTime)
|
|||
}
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
if (!mVideoPlaying) {
|
||||
if (!video->getScrollHide())
|
||||
video->onHide();
|
||||
else if (!video->hasStaticImage())
|
||||
video->onHide();
|
||||
else if (video->getOpacity() == 0.0f)
|
||||
video->onHide();
|
||||
}
|
||||
else if (mVideoPlaying && !video->isVideoPaused() && !mWindow->isScreensaverActive()) {
|
||||
video->onShow();
|
||||
}
|
||||
|
||||
if (ViewController::getInstance()->getGameLaunchTriggered() && video->isAnimationPlaying(0))
|
||||
video->finishAnimation(0);
|
||||
}
|
||||
|
||||
updateChildren(deltaTime);
|
||||
}
|
||||
|
||||
|
@ -375,6 +358,14 @@ void GamelistView::updateInfoPanel()
|
|||
|
||||
bool fadingOut = false;
|
||||
if (file == nullptr) {
|
||||
if (mVideoPlaying) {
|
||||
for (auto& video : mVideoComponents) {
|
||||
video->stopVideoPlayer();
|
||||
video->setVideo("");
|
||||
if (!video->hasStartDelay())
|
||||
video->setImage("");
|
||||
}
|
||||
}
|
||||
mVideoPlaying = false;
|
||||
fadingOut = true;
|
||||
}
|
||||
|
@ -393,17 +384,14 @@ void GamelistView::updateInfoPanel()
|
|||
for (auto& video : mVideoComponents) {
|
||||
setGameImage(mRandomGame, video.get());
|
||||
|
||||
// Always stop the video before setting a new video as it will otherwise
|
||||
// continue to play if it has the same path (i.e. it is the same physical
|
||||
// video file) as the previously set video. That may happen when entering a
|
||||
// folder with the same name as the first game file inside, or as in this
|
||||
// case, when entering a custom collection.
|
||||
video->onHide();
|
||||
video->stopVideoPlayer();
|
||||
|
||||
if (video->hasStaticVideo())
|
||||
video->setStaticVideo();
|
||||
else if (!video->setVideo(mRandomGame->getVideoPath()))
|
||||
video->setDefaultVideo();
|
||||
|
||||
video->startVideoPlayer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -413,10 +401,10 @@ void GamelistView::updateInfoPanel()
|
|||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
video->stopVideoPlayer();
|
||||
video->setImage("");
|
||||
video->setVideo("");
|
||||
if (video->hasStaticVideo()) {
|
||||
video->onStopVideo();
|
||||
video->setStaticVideo();
|
||||
}
|
||||
else {
|
||||
|
@ -426,17 +414,20 @@ void GamelistView::updateInfoPanel()
|
|||
}
|
||||
}
|
||||
else {
|
||||
for (auto& image : mImageComponents)
|
||||
for (auto& image : mImageComponents) {
|
||||
setGameImage(file, image.get());
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
setGameImage(file, video.get());
|
||||
video->onHide();
|
||||
video->stopVideoPlayer();
|
||||
|
||||
if (video->hasStaticVideo())
|
||||
video->setStaticVideo();
|
||||
else if (!video->setVideo(file->getVideoPath()))
|
||||
video->setDefaultVideo();
|
||||
|
||||
video->startVideoPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,28 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void startViewVideos() override
|
||||
{
|
||||
for (auto& video : mVideoComponents)
|
||||
video->startVideoPlayer();
|
||||
}
|
||||
void stopViewVideos() override
|
||||
{
|
||||
for (auto& video : mVideoComponents)
|
||||
video->stopVideoPlayer();
|
||||
}
|
||||
void pauseViewVideos() override
|
||||
{
|
||||
for (auto& video : mVideoComponents) {
|
||||
video->pauseVideoPlayer();
|
||||
}
|
||||
}
|
||||
void muteViewVideos() override
|
||||
{
|
||||
for (auto& video : mVideoComponents)
|
||||
video->muteVideoPlayer();
|
||||
}
|
||||
|
||||
const std::shared_ptr<ThemeData> getTheme() const { return mTheme; }
|
||||
void setTheme(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
|
|
|
@ -648,11 +648,6 @@ void ViewController::launch(FileData* game)
|
|||
return;
|
||||
}
|
||||
|
||||
// If the video view style is used, pause the video currently playing or block the
|
||||
// video from starting to play if the static image is still shown.
|
||||
if (mCurrentView)
|
||||
mCurrentView->onPauseVideo();
|
||||
|
||||
// Disable text scrolling and stop any Lottie animations. These will be enabled again in
|
||||
// FileData upon returning from the game.
|
||||
mWindow->setAllowTextScrolling(false);
|
||||
|
@ -806,7 +801,7 @@ bool ViewController::input(InputConfig* config, Input input)
|
|||
if (mWindow->getGameLaunchedState()) {
|
||||
mWindow->setAllowTextScrolling(true);
|
||||
mWindow->setAllowFileAnimation(true);
|
||||
mWindow->unsetLaunchedGame();
|
||||
mWindow->setLaunchedGame(false);
|
||||
// Filter out the "a" button so the game is not restarted if there was such a button press
|
||||
// queued when leaving the game.
|
||||
if (config->isMappedTo("a", input) && input.value != 0)
|
||||
|
@ -825,9 +820,12 @@ bool ViewController::input(InputConfig* config, Input input)
|
|||
// to play when we've closed the menu.
|
||||
if (mSystemListView->isSystemAnimationPlaying(0))
|
||||
mSystemListView->finishSystemAnimation(0);
|
||||
// Stop the gamelist scrolling as well as it would otherwise
|
||||
// also continue to run after closing the menu.
|
||||
// Stop the gamelist scrolling as well as it would otherwise continue to run after
|
||||
// closing the menu.
|
||||
mCurrentView->stopListScrolling();
|
||||
// Pause all videos as they would otherwise continue to play beneath the menu.
|
||||
mCurrentView->pauseViewVideos();
|
||||
|
||||
// Finally, if the camera is currently moving, reset its position.
|
||||
cancelViewTransitions();
|
||||
|
||||
|
@ -985,7 +983,7 @@ void ViewController::reloadGamelistView(GamelistView* view, bool reloadTheme)
|
|||
// video player, prevent scrolling of game names and game descriptions and prevent the
|
||||
// screensaver from starting on schedule.
|
||||
if (mWindow->getGameLaunchedState())
|
||||
mWindow->setLaunchedGame();
|
||||
mWindow->setLaunchedGame(true);
|
||||
|
||||
// Redisplay the current view.
|
||||
if (mCurrentView)
|
||||
|
|
|
@ -66,6 +66,12 @@ public:
|
|||
void cancelViewTransitions();
|
||||
void stopScrolling();
|
||||
|
||||
// Basic video controls.
|
||||
void startViewVideos() override { mCurrentView->startViewVideos(); }
|
||||
void stopViewVideos() override { mCurrentView->stopViewVideos(); }
|
||||
void pauseViewVideos() override { mCurrentView->pauseViewVideos(); }
|
||||
void muteViewVideos() override { mCurrentView->muteViewVideos(); }
|
||||
|
||||
void onFileChanged(FileData* file, bool reloadGamelist);
|
||||
void triggerGameLaunch(FileData* game)
|
||||
{
|
||||
|
|
|
@ -393,51 +393,3 @@ void GuiComponent::onHide()
|
|||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onHide();
|
||||
}
|
||||
|
||||
void GuiComponent::onStopVideo()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onStopVideo();
|
||||
}
|
||||
|
||||
void GuiComponent::onPauseVideo()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onPauseVideo();
|
||||
}
|
||||
|
||||
void GuiComponent::onUnpauseVideo()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onUnpauseVideo();
|
||||
}
|
||||
|
||||
void GuiComponent::onScreensaverActivate()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onScreensaverActivate();
|
||||
}
|
||||
|
||||
void GuiComponent::onScreensaverDeactivate()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onScreensaverDeactivate();
|
||||
}
|
||||
|
||||
void GuiComponent::onGameLaunchedActivate()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onGameLaunchedActivate();
|
||||
}
|
||||
|
||||
void GuiComponent::onGameLaunchedDeactivate()
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->onGameLaunchedDeactivate();
|
||||
}
|
||||
|
||||
void GuiComponent::topWindow(bool isTop)
|
||||
{
|
||||
for (unsigned int i = 0; i < getChildCount(); ++i)
|
||||
getChild(i)->topWindow(isTop);
|
||||
}
|
||||
|
|
|
@ -238,19 +238,16 @@ public:
|
|||
|
||||
virtual void onShow();
|
||||
virtual void onHide();
|
||||
virtual void onStopVideo();
|
||||
virtual void onPauseVideo();
|
||||
virtual void onUnpauseVideo();
|
||||
virtual bool isVideoPaused() { return false; }
|
||||
|
||||
// System view and gamelist view video controls.
|
||||
virtual void startViewVideos() {}
|
||||
virtual void stopViewVideos() {}
|
||||
virtual void pauseViewVideos() {}
|
||||
virtual void muteViewVideos() {}
|
||||
|
||||
// For Lottie animations.
|
||||
virtual void resetFileAnimation() {};
|
||||
|
||||
virtual void onScreensaverActivate();
|
||||
virtual void onScreensaverDeactivate();
|
||||
virtual void onGameLaunchedActivate();
|
||||
virtual void onGameLaunchedDeactivate();
|
||||
virtual void topWindow(bool isTop);
|
||||
|
||||
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
||||
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
|
|
|
@ -75,10 +75,6 @@ Window* Window::getInstance()
|
|||
|
||||
void Window::pushGui(GuiComponent* gui)
|
||||
{
|
||||
if (mGuiStack.size() > 0) {
|
||||
auto& top = mGuiStack.back();
|
||||
top->topWindow(false);
|
||||
}
|
||||
mGuiStack.push_back(gui);
|
||||
gui->updateHelpPrompts();
|
||||
}
|
||||
|
@ -90,10 +86,8 @@ void Window::removeGui(GuiComponent* gui)
|
|||
it = mGuiStack.erase(it);
|
||||
|
||||
// We just popped the stack and the stack is not empty.
|
||||
if (it == mGuiStack.cend() && mGuiStack.size()) {
|
||||
if (it == mGuiStack.cend() && mGuiStack.size())
|
||||
mGuiStack.back()->updateHelpPrompts();
|
||||
mGuiStack.back()->topWindow(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -752,10 +746,6 @@ void Window::stopInfoPopup()
|
|||
void Window::startScreensaver()
|
||||
{
|
||||
if (mScreensaver && !mRenderScreensaver) {
|
||||
// Tell the GUI components the screensaver is starting.
|
||||
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); ++it)
|
||||
(*it)->onScreensaverActivate();
|
||||
|
||||
setAllowTextScrolling(false);
|
||||
setAllowFileAnimation(false);
|
||||
mScreensaver->startScreensaver(true);
|
||||
|
@ -771,14 +761,6 @@ bool Window::stopScreensaver()
|
|||
setAllowTextScrolling(true);
|
||||
setAllowFileAnimation(true);
|
||||
|
||||
// Tell the GUI components the screensaver has stopped.
|
||||
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); ++it) {
|
||||
(*it)->onScreensaverDeactivate();
|
||||
// If the menu is open, pause the video so it won't start playing beneath the menu.
|
||||
if (mGuiStack.front() != mGuiStack.back())
|
||||
(*it)->onPauseVideo();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -830,10 +812,6 @@ void Window::closeLaunchScreen()
|
|||
mRenderLaunchScreen = false;
|
||||
}
|
||||
|
||||
void Window::increaseVideoPlayerCount() { ++mVideoPlayerCount; }
|
||||
|
||||
void Window::decreaseVideoPlayerCount() { --mVideoPlayerCount; }
|
||||
|
||||
int Window::getVideoPlayerCount()
|
||||
{
|
||||
int videoPlayerCount;
|
||||
|
@ -841,24 +819,6 @@ int Window::getVideoPlayerCount()
|
|||
return videoPlayerCount;
|
||||
}
|
||||
|
||||
void Window::setLaunchedGame()
|
||||
{
|
||||
// Tell the GUI components that a game has been launched.
|
||||
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); ++it)
|
||||
(*it)->onGameLaunchedActivate();
|
||||
|
||||
mGameLaunchedState = true;
|
||||
}
|
||||
|
||||
void Window::unsetLaunchedGame()
|
||||
{
|
||||
// Tell the GUI components that the user is back in ES-DE again.
|
||||
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); ++it)
|
||||
(*it)->onGameLaunchedDeactivate();
|
||||
|
||||
mGameLaunchedState = false;
|
||||
}
|
||||
|
||||
void Window::invalidateCachedBackground()
|
||||
{
|
||||
mCachedBackground = false;
|
||||
|
|
|
@ -130,12 +130,11 @@ public:
|
|||
void setLaunchScreen(GuiLaunchScreen* launchScreen) { mLaunchScreen = launchScreen; }
|
||||
bool isLaunchScreenDisplayed() { return mRenderLaunchScreen; }
|
||||
|
||||
void increaseVideoPlayerCount();
|
||||
void decreaseVideoPlayerCount();
|
||||
void increaseVideoPlayerCount() { ++mVideoPlayerCount; }
|
||||
void decreaseVideoPlayerCount() { --mVideoPlayerCount; }
|
||||
int getVideoPlayerCount();
|
||||
|
||||
void setLaunchedGame();
|
||||
void unsetLaunchedGame();
|
||||
void setLaunchedGame(bool state) { mGameLaunchedState = state; }
|
||||
void invalidateCachedBackground();
|
||||
bool isInvalidatingCachedBackground() { return mInvalidateCacheTimer > 0; }
|
||||
|
||||
|
|
|
@ -25,43 +25,36 @@ VideoComponent::VideoComponent()
|
|||
, mTargetSize {0.0f, 0.0f}
|
||||
, mVideoAreaPos {0.0f, 0.0f}
|
||||
, mVideoAreaSize {0.0f, 0.0f}
|
||||
, mStartDelayed {false}
|
||||
, mStartTime {0}
|
||||
, mIsPlaying {false}
|
||||
, mIsActuallyPlaying {false}
|
||||
, mPause {false}
|
||||
, mShowing {false}
|
||||
, mDisable {false}
|
||||
, mPaused {false}
|
||||
, mMediaViewerMode {false}
|
||||
, mScreensaverActive {false}
|
||||
, mScreensaverMode {false}
|
||||
, mGameLaunched {false}
|
||||
, mBlockPlayer {false}
|
||||
, mTargetIsMax {false}
|
||||
, mDrawPillarboxes {true}
|
||||
, mRenderScanlines {false}
|
||||
, mLegacyTheme {false}
|
||||
, mHasVideo {false}
|
||||
, mFadeIn {1.0f}
|
||||
, mFadeInTime {1000.0f}
|
||||
{
|
||||
// Setup the default configuration.
|
||||
// Setup default configuration.
|
||||
mConfig.showSnapshotDelay = false;
|
||||
mConfig.showSnapshotNoVideo = false;
|
||||
mConfig.startDelay = 1500;
|
||||
|
||||
if (mWindow->getGuiStackSize() > 1)
|
||||
topWindow(false);
|
||||
}
|
||||
|
||||
VideoComponent::~VideoComponent()
|
||||
{
|
||||
// Stop any currently running video.
|
||||
stopVideo();
|
||||
stopVideoPlayer();
|
||||
}
|
||||
|
||||
bool VideoComponent::setVideo(std::string path)
|
||||
{
|
||||
// Convert the path into a generic format.
|
||||
std::string fullPath = Utils::FileSystem::getCanonicalPath(path);
|
||||
std::string fullPath {Utils::FileSystem::getCanonicalPath(path)};
|
||||
|
||||
// Check that it's changed.
|
||||
if (fullPath == mVideoPath)
|
||||
|
@ -72,10 +65,17 @@ bool VideoComponent::setVideo(std::string path)
|
|||
|
||||
// If the file exists then set the new video.
|
||||
if (!fullPath.empty() && ResourceManager::getInstance().fileExists(fullPath)) {
|
||||
mHasVideo = true;
|
||||
// Return true to show that we are going to attempt to play a video.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mVideoPath.empty() || !mConfig.defaultVideoPath.empty() ||
|
||||
!mConfig.staticVideoPath.empty())
|
||||
mHasVideo = true;
|
||||
else
|
||||
mHasVideo = false;
|
||||
|
||||
// Return false to show that no video will be displayed.
|
||||
return false;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ void VideoComponent::setImage(const std::string& path, bool tile)
|
|||
if (imagePath == "")
|
||||
imagePath = mDefaultImagePath;
|
||||
|
||||
// Check that the image has changed.
|
||||
// Check if the image has changed.
|
||||
if (imagePath == mStaticImagePath)
|
||||
return;
|
||||
|
||||
|
@ -95,127 +95,6 @@ void VideoComponent::setImage(const std::string& path, bool tile)
|
|||
mStaticImagePath = imagePath;
|
||||
}
|
||||
|
||||
void VideoComponent::onShow()
|
||||
{
|
||||
mBlockPlayer = false;
|
||||
mPause = false;
|
||||
mShowing = true;
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onHide()
|
||||
{
|
||||
mShowing = false;
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onStopVideo()
|
||||
{
|
||||
stopVideo();
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onPauseVideo()
|
||||
{
|
||||
mBlockPlayer = true;
|
||||
mPause = true;
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onUnpauseVideo()
|
||||
{
|
||||
mBlockPlayer = false;
|
||||
mPause = false;
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onScreensaverActivate()
|
||||
{
|
||||
mBlockPlayer = true;
|
||||
mPause = true;
|
||||
|
||||
if (Settings::getInstance()->getString("ScreensaverType") == "dim")
|
||||
stopVideo();
|
||||
else
|
||||
pauseVideo();
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onScreensaverDeactivate()
|
||||
{
|
||||
mBlockPlayer = false;
|
||||
// Stop video when deactivating the screensaver to force a reload of the
|
||||
// static image (if the theme is configured as such).
|
||||
stopVideo();
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onGameLaunchedActivate()
|
||||
{
|
||||
mGameLaunched = true;
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::onGameLaunchedDeactivate()
|
||||
{
|
||||
mGameLaunched = false;
|
||||
stopVideo();
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::topWindow(bool isTop)
|
||||
{
|
||||
if (isTop) {
|
||||
mBlockPlayer = false;
|
||||
mPause = false;
|
||||
|
||||
// Stop video when closing the menu to force a reload of the
|
||||
// static image (if the theme is configured as such).
|
||||
stopVideo();
|
||||
}
|
||||
else {
|
||||
mBlockPlayer = true;
|
||||
mPause = true;
|
||||
}
|
||||
manageState();
|
||||
}
|
||||
|
||||
void VideoComponent::render(const glm::mat4& parentTrans)
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
glm::mat4 trans {parentTrans * getTransform()};
|
||||
GuiComponent::renderChildren(trans);
|
||||
|
||||
Renderer::setMatrix(trans);
|
||||
|
||||
// Handle the case where the video is delayed.
|
||||
handleStartDelay();
|
||||
|
||||
// Handle looping of the video.
|
||||
handleLooping();
|
||||
|
||||
// Pause video in case a game has been launched.
|
||||
pauseVideo();
|
||||
}
|
||||
|
||||
void VideoComponent::renderSnapshot(const glm::mat4& parentTrans)
|
||||
{
|
||||
// This function is called when the video is not currently being played. We need to
|
||||
// work out if we should display a static image. If the menu is open, then always render
|
||||
// the static image as the metadata may have been changed. In that case the gamelist
|
||||
// was reloaded and there would just be a blank space unless we render the image here.
|
||||
// The side effect of this is that a static image is displayed even for themes that are
|
||||
// set to start playing the video immediately. Although this may seem a bit inconsistent it
|
||||
// simply looks better than leaving an empty space where the video would have been located.
|
||||
if (mWindow->getGuiStackSize() > 1 || (mConfig.showSnapshotNoVideo && mVideoPath.empty()) ||
|
||||
(mStartDelayed && mConfig.showSnapshotDelay)) {
|
||||
mStaticImage.setOpacity(mOpacity * mThemeOpacity);
|
||||
mStaticImage.render(parentTrans);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view,
|
||||
const std::string& element,
|
||||
|
@ -327,12 +206,29 @@ std::vector<HelpPrompt> VideoComponent::getHelpPrompts()
|
|||
|
||||
void VideoComponent::update(int deltaTime)
|
||||
{
|
||||
if (mBlockPlayer) {
|
||||
setImage(mStaticImagePath);
|
||||
if (!mHasVideo) {
|
||||
// We need this update so the static image gets updated (e.g. used for fade animations).
|
||||
GuiComponent::update(deltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
manageState();
|
||||
// Hack to prevent the video from starting to play if the static image was shown when paused.
|
||||
if (mPaused)
|
||||
mStartTime = SDL_GetTicks() + mConfig.startDelay;
|
||||
|
||||
if (mWindow->getGameLaunchedState())
|
||||
return;
|
||||
|
||||
bool playVideo {false};
|
||||
|
||||
if (!mIsPlaying && mConfig.startDelay == 0) {
|
||||
startVideoStream();
|
||||
}
|
||||
else if (mStartTime == 0 || SDL_GetTicks() > mStartTime) {
|
||||
mStartTime = 0;
|
||||
playVideo = true;
|
||||
startVideoStream();
|
||||
}
|
||||
|
||||
// Fade in videos, the time period is a bit different between the screensaver and media viewer.
|
||||
// For the theme controlled videos in the gamelist and system views, the fade-in time is set
|
||||
|
@ -349,90 +245,37 @@ void VideoComponent::update(int deltaTime)
|
|||
mFadeIn = glm::clamp(mFadeIn + (deltaTime / static_cast<float>(mFadeInTime)), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (mIsPlaying)
|
||||
updatePlayer();
|
||||
|
||||
handleLooping();
|
||||
|
||||
GuiComponent::update(deltaTime);
|
||||
}
|
||||
|
||||
void VideoComponent::startVideoWithDelay()
|
||||
void VideoComponent::startVideoPlayer()
|
||||
{
|
||||
mPause = false;
|
||||
if (mIsPlaying)
|
||||
stopVideoPlayer();
|
||||
|
||||
// If not playing then either start the video or initiate the delay.
|
||||
if (!mIsPlaying) {
|
||||
// Set the video that we are going to be playing so we don't attempt to restart it.
|
||||
mPlayingVideoPath = mVideoPath;
|
||||
|
||||
if (mConfig.startDelay == 0) {
|
||||
// No delay. Just start the video.
|
||||
mStartDelayed = false;
|
||||
startVideo();
|
||||
}
|
||||
else {
|
||||
// Configure the start delay.
|
||||
mStartDelayed = true;
|
||||
mStartTime = SDL_GetTicks() + mConfig.startDelay;
|
||||
}
|
||||
mIsPlaying = true;
|
||||
if (mConfig.startDelay != 0 && mStaticImagePath != "") {
|
||||
mStartTime = SDL_GetTicks() + mConfig.startDelay;
|
||||
setImage(mStaticImagePath);
|
||||
}
|
||||
|
||||
mPaused = false;
|
||||
}
|
||||
|
||||
void VideoComponent::handleStartDelay()
|
||||
void VideoComponent::renderSnapshot(const glm::mat4& parentTrans)
|
||||
{
|
||||
if (mBlockPlayer || mGameLaunched)
|
||||
if (mLegacyTheme && !mHasVideo && !mConfig.showSnapshotNoVideo)
|
||||
return;
|
||||
|
||||
// Only play if any delay has timed out.
|
||||
if (mStartDelayed) {
|
||||
// If the setting to override the theme-supplied video delay setting has been enabled,
|
||||
// then play the video immediately.
|
||||
if (!Settings::getInstance()->getBool("PlayVideosImmediately")) {
|
||||
// If there is a video file available but no static image, then start playing the
|
||||
// video immediately regardless of theme configuration or settings.
|
||||
if (mStaticImagePath != "") {
|
||||
if (mStartTime > SDL_GetTicks()) {
|
||||
// Timeout not yet completed.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Completed.
|
||||
mStartDelayed = false;
|
||||
// Clear the playing flag so startVideo works.
|
||||
mIsPlaying = false;
|
||||
startVideo();
|
||||
if (mHasVideo && (!mConfig.showSnapshotDelay || mConfig.startDelay == 0))
|
||||
return;
|
||||
|
||||
if (mStaticImagePath != "") {
|
||||
mStaticImage.setOpacity(mOpacity * mThemeOpacity);
|
||||
mStaticImage.render(parentTrans);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoComponent::manageState()
|
||||
{
|
||||
// We will only show the video if the component is on display and the screensaver
|
||||
// is not active.
|
||||
bool show = mShowing && !mScreensaverActive && !mDisable;
|
||||
|
||||
// See if we're already playing.
|
||||
if (mIsPlaying) {
|
||||
// If we are not on display then stop the video from playing.
|
||||
if (!show) {
|
||||
stopVideo();
|
||||
}
|
||||
else {
|
||||
if (mVideoPath != mPlayingVideoPath) {
|
||||
// Path changed. Stop the video. We will start it again below because
|
||||
// mIsPlaying will be modified by stopVideo to be false.
|
||||
stopVideo();
|
||||
}
|
||||
}
|
||||
updatePlayer();
|
||||
}
|
||||
// Need to recheck variable rather than 'else' because it may be modified above.
|
||||
if (!mIsPlaying) {
|
||||
// If we are on display then see if we should start the video.
|
||||
if (show && !mVideoPath.empty())
|
||||
startVideoWithDelay();
|
||||
}
|
||||
|
||||
// If a game has just been launched and a video is actually shown, then request a
|
||||
// pause of the video so it doesn't continue to play in the background while the
|
||||
// game is running.
|
||||
if (mGameLaunched && show && !mPause)
|
||||
mPause = true;
|
||||
}
|
||||
|
|
|
@ -52,27 +52,19 @@ public:
|
|||
|
||||
bool hasStaticVideo() { return !mConfig.staticVideoPath.empty(); }
|
||||
bool hasStaticImage() { return mStaticImage.getTextureSize() != glm::ivec2 {0, 0}; }
|
||||
|
||||
void onShow() override;
|
||||
void onHide() override;
|
||||
void onStopVideo() override;
|
||||
void onPauseVideo() override;
|
||||
void onUnpauseVideo() override;
|
||||
bool isVideoPaused() override { return mPause; }
|
||||
void onScreensaverActivate() override;
|
||||
void onScreensaverDeactivate() override;
|
||||
void onGameLaunchedActivate() override;
|
||||
void onGameLaunchedDeactivate() override;
|
||||
void topWindow(bool isTop) override;
|
||||
bool hasStartDelay()
|
||||
{
|
||||
if (mLegacyTheme)
|
||||
return mConfig.showSnapshotDelay && mConfig.startDelay > 0;
|
||||
else
|
||||
return mConfig.startDelay > 0;
|
||||
}
|
||||
|
||||
// These functions update the embedded static image.
|
||||
void onOriginChanged() override { mStaticImage.setOrigin(mOrigin); }
|
||||
void onPositionChanged() override { mStaticImage.setPosition(mPosition); }
|
||||
void onSizeChanged() override { mStaticImage.onSizeChanged(); }
|
||||
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
void renderSnapshot(const glm::mat4& parentTrans);
|
||||
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view,
|
||||
const std::string& element,
|
||||
|
@ -95,27 +87,21 @@ public:
|
|||
virtual void setMaxSize(float width, float height) = 0;
|
||||
void setMaxSize(const glm::vec2& size) { setMaxSize(size.x, size.y); }
|
||||
|
||||
private:
|
||||
// Start the video immediately.
|
||||
virtual void startVideo() {}
|
||||
// Stop the video.
|
||||
virtual void stopVideo() {}
|
||||
// Pause the video when a game has been launched.
|
||||
virtual void pauseVideo() {}
|
||||
// Basic video controls.
|
||||
void startVideoPlayer();
|
||||
virtual void stopVideoPlayer() {}
|
||||
virtual void pauseVideoPlayer() {}
|
||||
|
||||
// Handle looping of the video. Must be called periodically.
|
||||
virtual void handleLooping() {}
|
||||
// Used to immediately mute audio even if there are still samples to play in the buffer.
|
||||
virtual void muteVideoPlayer() {}
|
||||
virtual void updatePlayer() {}
|
||||
|
||||
// Start the video after any configured delay.
|
||||
void startVideoWithDelay();
|
||||
// Handle any delay to the start of playing the video clip. Must be called periodically.
|
||||
void handleStartDelay();
|
||||
// Manage the playing state of the component.
|
||||
void manageState();
|
||||
|
||||
friend MediaViewer;
|
||||
|
||||
protected:
|
||||
virtual void startVideoStream() {}
|
||||
void renderSnapshot(const glm::mat4& parentTrans);
|
||||
|
||||
ImageComponent mStaticImage;
|
||||
|
||||
unsigned mVideoWidth;
|
||||
|
@ -128,23 +114,17 @@ protected:
|
|||
std::string mDefaultImagePath;
|
||||
|
||||
std::string mVideoPath;
|
||||
std::string mPlayingVideoPath;
|
||||
unsigned mStartTime;
|
||||
bool mStartDelayed;
|
||||
std::atomic<bool> mIsPlaying;
|
||||
std::atomic<bool> mIsActuallyPlaying;
|
||||
std::atomic<bool> mPause;
|
||||
bool mShowing;
|
||||
bool mDisable;
|
||||
std::atomic<bool> mPaused;
|
||||
bool mMediaViewerMode;
|
||||
bool mScreensaverActive;
|
||||
bool mScreensaverMode;
|
||||
bool mGameLaunched;
|
||||
bool mBlockPlayer;
|
||||
bool mTargetIsMax;
|
||||
bool mDrawPillarboxes;
|
||||
bool mRenderScanlines;
|
||||
bool mLegacyTheme;
|
||||
bool mHasVideo;
|
||||
float mFadeIn;
|
||||
float mFadeInTime;
|
||||
|
||||
|
|
|
@ -54,8 +54,6 @@ VideoFFmpegComponent::VideoFFmpegComponent()
|
|||
{
|
||||
}
|
||||
|
||||
VideoFFmpegComponent::~VideoFFmpegComponent() { stopVideo(); }
|
||||
|
||||
void VideoFFmpegComponent::setResize(float width, float height)
|
||||
{
|
||||
// This resize function is used when stretching videos to full screen in the video screensaver.
|
||||
|
@ -126,7 +124,9 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
|||
if (!isVisible() || mThemeOpacity == 0.0f)
|
||||
return;
|
||||
|
||||
VideoComponent::render(parentTrans);
|
||||
if (!mHasVideo && mStaticImagePath == "")
|
||||
return;
|
||||
|
||||
glm::mat4 trans {parentTrans * getTransform()};
|
||||
GuiComponent::renderChildren(trans);
|
||||
|
||||
|
@ -209,7 +209,8 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
|||
pictureLock.unlock();
|
||||
}
|
||||
|
||||
mTexture->bind();
|
||||
if (mTexture != nullptr)
|
||||
mTexture->bind();
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Render scanlines if this option is enabled. However, if this is the media viewer
|
||||
|
@ -239,7 +240,7 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
|||
|
||||
void VideoFFmpegComponent::updatePlayer()
|
||||
{
|
||||
if (mPause || !mFormatContext)
|
||||
if (mPaused || !mFormatContext)
|
||||
return;
|
||||
|
||||
// Output any audio that has been added by the processing thread.
|
||||
|
@ -282,7 +283,7 @@ void VideoFFmpegComponent::frameProcessing()
|
|||
if (mAudioCodecContext)
|
||||
audioFilter = setupAudioFilters();
|
||||
|
||||
while (mIsPlaying && !mPause && videoFilter && (!mAudioCodecContext || audioFilter)) {
|
||||
while (mIsPlaying && !mPaused && videoFilter && (!mAudioCodecContext || audioFilter)) {
|
||||
readFrames();
|
||||
if (!mIsPlaying)
|
||||
break;
|
||||
|
@ -1073,7 +1074,7 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
AVCodecContext* checkCodecContext = avcodec_alloc_context3(mHardwareCodec);
|
||||
|
||||
if (avcodec_parameters_to_context(checkCodecContext, mVideoStream->codecpar)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::decoderInitHW(): "
|
||||
"Couldn't fill the video codec context parameters for file \""
|
||||
<< mVideoPath << "\"";
|
||||
avcodec_free_context(&checkCodecContext);
|
||||
|
@ -1086,7 +1087,7 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
checkCodecContext->hw_device_ctx = av_buffer_ref(mHwContext);
|
||||
|
||||
if (avcodec_open2(checkCodecContext, mHardwareCodec, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::decoderInitHW(): "
|
||||
"Couldn't initialize the video codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
}
|
||||
|
@ -1174,7 +1175,7 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
mVideoCodecContext = avcodec_alloc_context3(mHardwareCodec);
|
||||
|
||||
if (!mVideoCodecContext) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::decoderInitHW(): "
|
||||
"Couldn't allocate video codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
avcodec_free_context(&mVideoCodecContext);
|
||||
|
@ -1182,7 +1183,7 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
}
|
||||
|
||||
if (avcodec_parameters_to_context(mVideoCodecContext, mVideoStream->codecpar)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::decoderInitHW(): "
|
||||
"Couldn't fill the video codec context parameters for file \""
|
||||
<< mVideoPath << "\"";
|
||||
avcodec_free_context(&mVideoCodecContext);
|
||||
|
@ -1193,7 +1194,7 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
mVideoCodecContext->hw_device_ctx = av_buffer_ref(mHwContext);
|
||||
|
||||
if (avcodec_open2(mVideoCodecContext, mHardwareCodec, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::decoderInitHW(): "
|
||||
"Couldn't initialize the video codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
avcodec_free_context(&mVideoCodecContext);
|
||||
|
@ -1203,8 +1204,10 @@ bool VideoFFmpegComponent::decoderInitHW()
|
|||
return false;
|
||||
}
|
||||
|
||||
void VideoFFmpegComponent::startVideo()
|
||||
void VideoFFmpegComponent::startVideoStream()
|
||||
{
|
||||
mIsPlaying = true;
|
||||
|
||||
if (!mFormatContext) {
|
||||
mHardwareCodec = nullptr;
|
||||
mHwContext = nullptr;
|
||||
|
@ -1240,14 +1243,14 @@ void VideoFFmpegComponent::startVideo()
|
|||
// File operations and basic setup.
|
||||
|
||||
if (avformat_open_input(&mFormatContext, filePath.c_str(), nullptr, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't open video file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
if (avformat_find_stream_info(mFormatContext, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't read stream information from video file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
|
@ -1268,7 +1271,7 @@ void VideoFFmpegComponent::startVideo()
|
|||
av_find_best_stream(mFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &mHardwareCodec, 0);
|
||||
|
||||
if (mVideoStreamIndex < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't retrieve video stream for file \""
|
||||
<< mVideoPath << "\"";
|
||||
avformat_close_input(&mFormatContext);
|
||||
|
@ -1280,7 +1283,7 @@ void VideoFFmpegComponent::startVideo()
|
|||
mVideoWidth = mFormatContext->streams[mVideoStreamIndex]->codecpar->width;
|
||||
mVideoHeight = mFormatContext->streams[mVideoStreamIndex]->codecpar->height;
|
||||
|
||||
LOG(LogDebug) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogDebug) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
<< "Playing video \"" << mVideoPath << "\" (codec: "
|
||||
<< avcodec_get_name(
|
||||
mFormatContext->streams[mVideoStreamIndex]->codecpar->codec_id)
|
||||
|
@ -1294,15 +1297,16 @@ void VideoFFmpegComponent::startVideo()
|
|||
if (mSWDecoder) {
|
||||
// The hardware decoder initialization failed, which can happen for a number of reasons.
|
||||
if (hwDecoding) {
|
||||
LOG(LogDebug) << "VideoFFmpegComponent::startVideo(): Hardware decoding failed, "
|
||||
"falling back to software decoder";
|
||||
LOG(LogDebug)
|
||||
<< "VideoFFmpegComponent::startVideoStream(): Hardware decoding failed, "
|
||||
"falling back to software decoder";
|
||||
}
|
||||
|
||||
mVideoCodec =
|
||||
const_cast<AVCodec*>(avcodec_find_decoder(mVideoStream->codecpar->codec_id));
|
||||
|
||||
if (!mVideoCodec) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't find a suitable video codec for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
|
@ -1311,7 +1315,7 @@ void VideoFFmpegComponent::startVideo()
|
|||
mVideoCodecContext = avcodec_alloc_context3(mVideoCodec);
|
||||
|
||||
if (!mVideoCodecContext) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't allocate video codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
|
@ -1321,14 +1325,14 @@ void VideoFFmpegComponent::startVideo()
|
|||
mVideoCodecContext->flags |= AV_CODEC_FLAG_TRUNCATED;
|
||||
|
||||
if (avcodec_parameters_to_context(mVideoCodecContext, mVideoStream->codecpar)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't fill the video codec context parameters for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
if (avcodec_open2(mVideoCodecContext, mVideoCodec, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't initialize the video codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
|
@ -1341,7 +1345,7 @@ void VideoFFmpegComponent::startVideo()
|
|||
av_find_best_stream(mFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
|
||||
|
||||
if (mAudioStreamIndex < 0) {
|
||||
LOG(LogDebug) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogDebug) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"File does not seem to contain any audio streams";
|
||||
}
|
||||
|
||||
|
@ -1366,14 +1370,14 @@ void VideoFFmpegComponent::startVideo()
|
|||
mAudioCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
||||
if (avcodec_parameters_to_context(mAudioCodecContext, mAudioStream->codecpar)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't fill the audio codec context parameters for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
if (avcodec_open2(mAudioCodecContext, mAudioCodec, nullptr)) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideo(): "
|
||||
LOG(LogError) << "VideoFFmpegComponent::startVideoStream(): "
|
||||
"Couldn't initialize the audio codec context for file \""
|
||||
<< mVideoPath << "\"";
|
||||
return;
|
||||
|
@ -1402,17 +1406,17 @@ void VideoFFmpegComponent::startVideo()
|
|||
// Calculate pillarbox/letterbox sizes.
|
||||
calculateBlackRectangle();
|
||||
|
||||
mIsPlaying = true;
|
||||
mFadeIn = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoFFmpegComponent::stopVideo()
|
||||
void VideoFFmpegComponent::stopVideoPlayer()
|
||||
{
|
||||
muteVideoPlayer();
|
||||
|
||||
mIsPlaying = false;
|
||||
mIsActuallyPlaying = false;
|
||||
mStartDelayed = false;
|
||||
mPause = false;
|
||||
mPaused = false;
|
||||
mEndOfVideo = false;
|
||||
mTexture.reset();
|
||||
|
||||
|
@ -1451,10 +1455,10 @@ void VideoFFmpegComponent::stopVideo()
|
|||
}
|
||||
}
|
||||
|
||||
void VideoFFmpegComponent::pauseVideo()
|
||||
void VideoFFmpegComponent::pauseVideoPlayer()
|
||||
{
|
||||
if (mPause && mWindow->getVideoPlayerCount() == 0)
|
||||
AudioManager::getInstance().muteStream();
|
||||
muteVideoPlayer();
|
||||
mPaused = true;
|
||||
}
|
||||
|
||||
void VideoFFmpegComponent::handleLooping()
|
||||
|
@ -1467,8 +1471,16 @@ void VideoFFmpegComponent::handleLooping()
|
|||
mWindow->screensaverTriggerNextGame();
|
||||
}
|
||||
else {
|
||||
stopVideo();
|
||||
startVideo();
|
||||
stopVideoPlayer();
|
||||
startVideoStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoFFmpegComponent::muteVideoPlayer()
|
||||
{
|
||||
if (AudioManager::sAudioDevice != 0) {
|
||||
AudioManager::getInstance().clearStream();
|
||||
AudioManager::getInstance().muteStream();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class VideoFFmpegComponent : public VideoComponent
|
|||
{
|
||||
public:
|
||||
VideoFFmpegComponent();
|
||||
virtual ~VideoFFmpegComponent();
|
||||
virtual ~VideoFFmpegComponent() { stopVideoPlayer(); }
|
||||
|
||||
// Resize the video to fit this size. If one axis is zero, scale that axis to maintain
|
||||
// aspect ratio. If both are non-zero, potentially break the aspect ratio. If both are
|
||||
|
@ -45,8 +45,17 @@ public:
|
|||
// This can be set before or after a video is loaded.
|
||||
// Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive.
|
||||
void setMaxSize(float width, float height) override;
|
||||
// Basic video controls.
|
||||
void stopVideoPlayer() override;
|
||||
void pauseVideoPlayer() override;
|
||||
// Handle looping of the video. Must be called periodically.
|
||||
void handleLooping() override;
|
||||
// Used to immediately mute audio even if there are samples to play in the buffer.
|
||||
void muteVideoPlayer() override;
|
||||
|
||||
private:
|
||||
void startVideoStream() override;
|
||||
|
||||
// Calculates the correct mSize from our resizing information (set by setResize/setMaxSize).
|
||||
// Used internally whenever the resizing parameters or texture change.
|
||||
void resize();
|
||||
|
@ -74,15 +83,6 @@ private:
|
|||
static void detectHWDecoder();
|
||||
bool decoderInitHW();
|
||||
|
||||
// Start the video immediately.
|
||||
void startVideo() override;
|
||||
// Stop the video.
|
||||
void stopVideo() override;
|
||||
// Pause the video when a game has been launched.
|
||||
void pauseVideo() override;
|
||||
// Handle looping the video. Must be called periodically.
|
||||
void handleLooping() override;
|
||||
|
||||
static enum AVHWDeviceType sDeviceType;
|
||||
static enum AVPixelFormat sPixelFormat;
|
||||
static std::vector<std::string> sSWDecodedVideos;
|
||||
|
|
Loading…
Reference in a new issue