Merge pull request #153 from pjft/RetroPie-ScreenSaver-Merge

Adding Random Video Screensaver/Attract Mode, plus controls
This commit is contained in:
Jools Wills 2017-06-12 16:43:41 +01:00 committed by GitHub
commit 2188efd2b6
27 changed files with 891 additions and 123 deletions

View file

@ -11,6 +11,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Gamelist.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileFilterIndex.h
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemScreenSaver.h
# GuiComponents
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AsyncReqComponent.h
@ -23,6 +24,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiGameScraper.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiGamelistOptions.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScreensaverOptions.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSettings.h
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.h
@ -60,6 +62,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Gamelist.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/FileFilterIndex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemScreenSaver.cpp
# GuiComponents
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AsyncReqComponent.cpp
@ -71,6 +74,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiGameScraper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiGamelistOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScreensaverOptions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiSettings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.cpp

View file

@ -0,0 +1,318 @@
#include "SystemScreenSaver.h"
#ifdef _RPI_
#include "components/VideoPlayerComponent.h"
#endif
#include "components/VideoVlcComponent.h"
#include "platform.h"
#include "Renderer.h"
#include "Settings.h"
#include "SystemData.h"
#include "Util.h"
#include "Log.h"
#include "views/ViewController.h"
#include "views/gamelist/IGameListView.h"
#include <stdio.h>
#define FADE_TIME 300
#define SWAP_VIDEO_TIMEOUT 30000
SystemScreenSaver::SystemScreenSaver(Window* window) :
mVideoScreensaver(NULL),
mWindow(window),
mCounted(false),
mVideoCount(0),
mState(STATE_INACTIVE),
mOpacity(0.0f),
mTimer(0),
mSystemName(""),
mGameName(""),
mCurrentGame(NULL)
{
mWindow->setScreenSaver(this);
std::string path = getTitleFolder();
if(!boost::filesystem::exists(path))
boost::filesystem::create_directory(path);
srand((unsigned int)time(NULL));
}
SystemScreenSaver::~SystemScreenSaver()
{
// Delete subtitle file, if existing
remove(getTitlePath().c_str());
mCurrentGame = NULL;
delete mVideoScreensaver;
}
bool SystemScreenSaver::allowSleep()
{
//return false;
return (mVideoScreensaver == NULL);
}
bool SystemScreenSaver::isScreenSaverActive()
{
return (mState != STATE_INACTIVE);
}
void SystemScreenSaver::startScreenSaver()
{
if (!mVideoScreensaver && (Settings::getInstance()->getString("ScreenSaverBehavior") == "random video"))
{
// Configure to fade out the windows
mState = STATE_FADE_OUT_WINDOW;
mOpacity = 0.0f;
// Load a random video
std::string path = "";
pickRandomVideo(path);
int retry = 200;
while(retry > 0 && ((path.empty() || !boost::filesystem::exists(path)) || mCurrentGame == NULL))
{
retry--;
pickRandomVideo(path);
}
if (!path.empty() && boost::filesystem::exists(path))
{
// Create the correct type of video component
#ifdef _RPI_
if (Settings::getInstance()->getBool("ScreenSaverOmxPlayer"))
mVideoScreensaver = new VideoPlayerComponent(mWindow, getTitlePath());
else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#endif
mVideoScreensaver->setOrigin(0.5f, 0.5f);
mVideoScreensaver->setPosition(Renderer::getScreenWidth()/2, Renderer::getScreenHeight()/2);
if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver"))
{
mVideoScreensaver->setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
else
{
mVideoScreensaver->setMaxSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mVideoScreensaver->setVideo(path);
mVideoScreensaver->setScreensaverMode(true);
mVideoScreensaver->onShow();
mTimer = 0;
return;
}
}
// No videos. Just use a standard screensaver
mState = STATE_SCREENSAVER_ACTIVE;
mCurrentGame = NULL;
}
void SystemScreenSaver::stopScreenSaver()
{
delete mVideoScreensaver;
mVideoScreensaver = NULL;
mState = STATE_INACTIVE;
}
void SystemScreenSaver::renderScreenSaver()
{
if (mVideoScreensaver && Settings::getInstance()->getString("ScreenSaverBehavior") == "random video")
{
// Render black background
Renderer::setMatrix(Eigen::Affine3f::Identity());
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), (unsigned char)(255));
// Only render the video if the state requires it
if ((int)mState >= STATE_FADE_IN_VIDEO)
{
Eigen::Affine3f transform = Eigen::Affine3f::Identity();
mVideoScreensaver->render(transform);
}
}
else if (mState != STATE_INACTIVE)
{
Renderer::setMatrix(Eigen::Affine3f::Identity());
unsigned char opacity = Settings::getInstance()->getString("ScreenSaverBehavior") == "dim" ? 0xA0 : 0xFF;
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x00000000 | opacity);
}
}
void SystemScreenSaver::countVideos()
{
if (!mCounted)
{
mVideoCount = 0;
mCounted = true;
std::vector<SystemData*>:: iterator it;
for (it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); ++it)
{
pugi::xml_document doc;
pugi::xml_node root;
std::string xmlReadPath = (*it)->getGamelistPath(false);
if(boost::filesystem::exists(xmlReadPath))
{
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
if (!result)
continue;
root = doc.child("gameList");
if (!root)
continue;
for(pugi::xml_node fileNode = root.child("game"); fileNode; fileNode = fileNode.next_sibling("game"))
{
pugi::xml_node videoNode = fileNode.child("video");
if (videoNode)
++mVideoCount;
}
}
}
}
}
void SystemScreenSaver::pickRandomVideo(std::string& path)
{
countVideos();
mCurrentGame = NULL;
if (mVideoCount > 0)
{
int video = (int)(((float)rand() / float(RAND_MAX)) * (float)mVideoCount);
std::vector<SystemData*>:: iterator it;
for (it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); ++it)
{
pugi::xml_document doc;
pugi::xml_node root;
std::string xmlReadPath = (*it)->getGamelistPath(false);
if(boost::filesystem::exists(xmlReadPath))
{
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
if (!result)
continue;
root = doc.child("gameList");
if (!root)
continue;
for(pugi::xml_node fileNode = root.child("game"); fileNode; fileNode = fileNode.next_sibling("game"))
{
pugi::xml_node videoNode = fileNode.child("video");
if (videoNode)
{
// See if this is the randomly selected video
if (video-- == 0)
{
// Yes. Resolve to a full path
path = resolvePath(videoNode.text().get(), (*it)->getStartPath(), true).generic_string();
mSystemName = (*it)->getFullName();
mGameName = fileNode.child("name").text().get();
// getting corresponding FileData
// try the easy way. Should work for the majority of cases, unless in subfolders
FileData* rootFileData = (*it)->getRootFolder();
std::string gamePath = resolvePath(fileNode.child("path").text().get(), (*it)->getStartPath(), false).string();
std::string shortPath = gamePath;
shortPath = shortPath.replace(0, (*it)->getStartPath().length()+1, "");
const std::unordered_map<std::string, FileData*>& children = rootFileData->getChildrenByFilename();
std::unordered_map<std::string, FileData*>::const_iterator screenSaverGame = children.find(shortPath);
if (screenSaverGame != children.end())
{
// Found the corresponding FileData
mCurrentGame = screenSaverGame->second;
}
else
{
// Couldn't find FileData. Going for the full iteration.
// iterate on children
FileType type = GAME;
std::vector<FileData*> allFiles = rootFileData->getFilesRecursive(type);
std::vector<FileData*>::iterator itf; // declare an iterator to a vector of strings
int i = 0;
for(itf=allFiles.begin() ; itf < allFiles.end(); itf++,i++ ) {
if ((*itf)->getPath() == gamePath)
{
mCurrentGame = (*itf);
break;
}
}
}
// end of getting FileData
if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never")
writeSubtitle(mGameName.c_str(), mSystemName.c_str(),
(Settings::getInstance()->getString("ScreenSaverGameInfo") == "always"));
return;
}
}
}
}
}
}
}
void SystemScreenSaver::update(int deltaTime)
{
// Use this to update the fade value for the current fade stage
if (mState == STATE_FADE_OUT_WINDOW)
{
mOpacity += (float)deltaTime / FADE_TIME;
if (mOpacity >= 1.0f)
{
mOpacity = 1.0f;
// Update to the next state
mState = STATE_FADE_IN_VIDEO;
}
}
else if (mState == STATE_FADE_IN_VIDEO)
{
mOpacity -= (float)deltaTime / FADE_TIME;
if (mOpacity <= 0.0f)
{
mOpacity = 0.0f;
// Update to the next state
mState = STATE_SCREENSAVER_ACTIVE;
}
}
else if (mState == STATE_SCREENSAVER_ACTIVE)
{
// Update the timer that swaps the videos
mTimer += deltaTime;
if (mTimer > SWAP_VIDEO_TIMEOUT)
{
nextVideo();
}
}
// If we have a loaded video then update it
if (mVideoScreensaver)
mVideoScreensaver->update(deltaTime);
}
void SystemScreenSaver::nextVideo() {
stopScreenSaver();
startScreenSaver();
mState = STATE_SCREENSAVER_ACTIVE;
}
FileData* SystemScreenSaver::getCurrentGame()
{
return mCurrentGame;
}
void SystemScreenSaver::launchGame()
{
// launching Game
ViewController::get()->goToGameList(mCurrentGame->getSystem());
IGameListView* view = ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
view->setCursor(mCurrentGame);
if (Settings::getInstance()->getBool("ScreenSaverControls"))
{
view->launch(mCurrentGame);
}
}

View file

@ -0,0 +1,49 @@
#pragma once
#include "Window.h"
class VideoComponent;
// Screensaver implementation for main window
class SystemScreenSaver : public Window::ScreenSaver
{
public:
SystemScreenSaver(Window* window);
virtual ~SystemScreenSaver();
virtual void startScreenSaver();
virtual void stopScreenSaver();
virtual void nextVideo();
virtual void renderScreenSaver();
virtual bool allowSleep();
virtual void update(int deltaTime);
virtual bool isScreenSaverActive();
virtual FileData* getCurrentGame();
virtual void launchGame();
private:
void countVideos();
void pickRandomVideo(std::string& path);
void input(InputConfig* config, Input input);
enum STATE {
STATE_INACTIVE,
STATE_FADE_OUT_WINDOW,
STATE_FADE_IN_VIDEO,
STATE_SCREENSAVER_ACTIVE
};
private:
bool mCounted;
unsigned long mVideoCount;
VideoComponent* mVideoScreensaver;
Window* mWindow;
STATE mState;
float mOpacity;
int mTimer;
FileData* mCurrentGame;
std::string mGameName;
std::string mSystemName;
};

View file

@ -6,6 +6,7 @@
#include "Settings.h"
#include "guis/GuiMsgBox.h"
#include "guis/GuiSettings.h"
#include "guis/GuiScreensaverOptions.h"
#include "guis/GuiScraperStart.h"
#include "guis/GuiDetectDevice.h"
#include "views/ViewController.h"
@ -98,6 +99,30 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addWithLabel("ENABLE NAVIGATION SOUNDS", sounds_enabled);
s->addSaveFunc([sounds_enabled] { Settings::getInstance()->setBool("EnableSounds", sounds_enabled->getState()); });
auto video_audio = std::make_shared<SwitchComponent>(mWindow);
video_audio->setState(Settings::getInstance()->getBool("VideoAudio"));
s->addWithLabel("ENABLE VIDEO AUDIO", video_audio);
s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("VideoAudio", video_audio->getState()); });
#ifdef _RPI_
// OMX player Audio Device
auto omx_audio_dev = std::make_shared< OptionListComponent<std::string> >(mWindow, "OMX PLAYER AUDIO DEVICE", false);
std::vector<std::string> devices;
devices.push_back("local");
devices.push_back("hdmi");
devices.push_back("both");
// USB audio
devices.push_back("alsa:hw:0,0");
devices.push_back("alsa:hw:1,0");
for (auto it = devices.begin(); it != devices.end(); it++)
omx_audio_dev->add(*it, *it, Settings::getInstance()->getString("OMXAudioDev") == *it);
s->addWithLabel("OMX PLAYER AUDIO DEVICE", omx_audio_dev);
s->addSaveFunc([omx_audio_dev] {
if (Settings::getInstance()->getString("OMXAudioDev") != omx_audio_dev->getSelected())
Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected());
});
#endif
mWindow->pushGui(s);
});
@ -112,26 +137,32 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addSaveFunc([screensaver_time] { Settings::getInstance()->setInt("ScreenSaverTime", (int)round(screensaver_time->getValue()) * (1000 * 60)); });
// screensaver behavior
auto screensaver_behavior = std::make_shared< OptionListComponent<std::string> >(mWindow, "TRANSITION STYLE", false);
auto screensaver_behavior = std::make_shared< OptionListComponent<std::string> >(mWindow, "SCREENSAVER BEHAVIOR", false);
std::vector<std::string> screensavers;
screensavers.push_back("dim");
screensavers.push_back("black");
screensavers.push_back("random video");
for(auto it = screensavers.begin(); it != screensavers.end(); it++)
screensaver_behavior->add(*it, *it, Settings::getInstance()->getString("ScreenSaverBehavior") == *it);
s->addWithLabel("SCREENSAVER BEHAVIOR", screensaver_behavior);
s->addSaveFunc([screensaver_behavior] { Settings::getInstance()->setString("ScreenSaverBehavior", screensaver_behavior->getSelected()); });
s->addSaveFunc([this, screensaver_behavior] {
if (Settings::getInstance()->getString("ScreenSaverBehavior") != "random video" && screensaver_behavior->getSelected() == "random video") {
// if before it wasn't risky but now there's a risk of problems, show warning
mWindow->pushGui(new GuiMsgBox(mWindow,
"The \"Random Video\" screensaver shows videos from your gamelist.\n\nIf you do not have videos, or if in several consecutive attempts the games it selects don't have videos it will default to black.\n\nMore options in the \"UI Settings\" > \"Video Screensaver\" menu.",
"OK", [] { return; }));
}
Settings::getInstance()->setString("ScreenSaverBehavior", screensaver_behavior->getSelected());
});
// framerate
auto framerate = std::make_shared<SwitchComponent>(mWindow);
framerate->setState(Settings::getInstance()->getBool("DrawFramerate"));
s->addWithLabel("SHOW FRAMERATE", framerate);
s->addSaveFunc([framerate] { Settings::getInstance()->setBool("DrawFramerate", framerate->getState()); });
ComponentListRow row;
// show help
auto show_help = std::make_shared<SwitchComponent>(mWindow);
show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts"));
s->addWithLabel("ON-SCREEN HELP", show_help);
s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", show_help->getState()); });
// show filtered menu
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
row.addElement(makeArrow(mWindow), false);
row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
s->addRow(row);
// quick system select (left/right in game list view)
auto quick_sys_select = std::make_shared<SwitchComponent>(mWindow);
@ -197,52 +228,12 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
if (needReload)
ViewController::get()->reloadAll();
});
mWindow->pushGui(s);
});
addEntry("VIDEO PLAYER SETTINGS", 0x777777FF, true,
[this] {
auto s = new GuiSettings(mWindow, "VIDEO PLAYER SETTINGS");
#ifdef _RPI_
// Video Player - VideoOmxPlayer
auto omx_player = std::make_shared<SwitchComponent>(mWindow);
omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer"));
s->addWithLabel("USE OMX VIDEO PLAYER (HW ACCELERATED)", omx_player);
s->addSaveFunc([omx_player]
{
// need to reload all views to re-create the right video components
bool needReload = false;
if(Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState())
needReload = true;
Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState());
if(needReload)
ViewController::get()->reloadAll();
});
// OMX player Audio Device
auto omx_audio_dev = std::make_shared< OptionListComponent<std::string> >(mWindow, "OMX PLAYER AUDIO DEVICE", false);
std::vector<std::string> devices;
devices.push_back("local");
devices.push_back("hdmi");
devices.push_back("both");
// USB audio
devices.push_back("alsa:hw:0,0");
devices.push_back("alsa:hw:1,0");
for (auto it = devices.begin(); it != devices.end(); it++)
omx_audio_dev->add(*it, *it, Settings::getInstance()->getString("OMXAudioDev") == *it);
s->addWithLabel("OMX PLAYER AUDIO DEVICE", omx_audio_dev);
s->addSaveFunc([omx_audio_dev] {
if (Settings::getInstance()->getString("OMXAudioDev") != omx_audio_dev->getSelected())
Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected());
});
#endif
auto video_audio = std::make_shared<SwitchComponent>(mWindow);
video_audio->setState(Settings::getInstance()->getBool("VideoAudio"));
s->addWithLabel("ENABLE VIDEO AUDIO", video_audio);
s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("VideoAudio", video_audio->getState()); });
// show help
auto show_help = std::make_shared<SwitchComponent>(mWindow);
show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts"));
s->addWithLabel("ON-SCREEN HELP", show_help);
s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", show_help->getState()); });
mWindow->pushGui(s);
});
@ -262,12 +253,39 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addWithLabel("PARSE GAMESLISTS ONLY", parse_gamelists);
s->addSaveFunc([parse_gamelists] { Settings::getInstance()->setBool("ParseGamelistOnly", parse_gamelists->getState()); });
#ifdef _RPI_
// Video Player - VideoOmxPlayer
auto omx_player = std::make_shared<SwitchComponent>(mWindow);
omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer"));
s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", omx_player);
s->addSaveFunc([omx_player]
{
// need to reload all views to re-create the right video components
bool needReload = false;
if(Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState())
needReload = true;
Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState());
if(needReload)
ViewController::get()->reloadAll();
});
#endif
// maximum vram
auto max_vram = std::make_shared<SliderComponent>(mWindow, 0.f, 1000.f, 10.f, "Mb");
max_vram->setValue((float)(Settings::getInstance()->getInt("MaxVRAM")));
s->addWithLabel("VRAM LIMIT", max_vram);
s->addSaveFunc([max_vram] { Settings::getInstance()->setInt("MaxVRAM", (int)round(max_vram->getValue())); });
// framerate
auto framerate = std::make_shared<SwitchComponent>(mWindow);
framerate->setState(Settings::getInstance()->getBool("DrawFramerate"));
s->addWithLabel("SHOW FRAMERATE", framerate);
s->addSaveFunc([framerate] { Settings::getInstance()->setBool("DrawFramerate", framerate->getState()); });
mWindow->pushGui(s);
});
@ -350,6 +368,11 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f);
}
void GuiMenu::openScreensaverOptions() {
GuiScreensaverOptions* ggf = new GuiScreensaverOptions(mWindow, "VIDEO SCREENSAVER");
mWindow->pushGui(ggf);
}
void GuiMenu::onSizeChanged()
{
mVersion.setSize(mSize.x(), 0);

View file

@ -16,7 +16,7 @@ public:
private:
void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
void openScreensaverOptions();
MenuComponent mMenu;
TextComponent mVersion;
};

View file

@ -0,0 +1,125 @@
#include "guis/GuiScreensaverOptions.h"
#include "Window.h"
#include "Settings.h"
#include "views/ViewController.h"
#include "components/ButtonComponent.h"
#include "components/SwitchComponent.h"
#include "components/SliderComponent.h"
#include "components/TextComponent.h"
#include "components/OptionListComponent.h"
#include "components/MenuComponent.h"
#include "guis/GuiMsgBox.h"
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const char* title) : GuiComponent(window), mMenu(window, title)
{
addChild(&mMenu);
#ifdef _RPI_
auto ss_omx = std::make_shared<SwitchComponent>(mWindow);
ss_omx->setState(Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
addWithLabel("USE OMX PLAYER FOR SCREENSAVER", ss_omx);
addSaveFunc([ss_omx, this] { Settings::getInstance()->setBool("ScreenSaverOmxPlayer", ss_omx->getState()); });
#endif
// Allow ScreenSaver Controls - ScreenSaverControls
auto ss_controls = std::make_shared<SwitchComponent>(mWindow);
ss_controls->setState(Settings::getInstance()->getBool("ScreenSaverControls"));
addWithLabel("SCREENSAVER CONTROLS", ss_controls);
addSaveFunc([ss_controls] { Settings::getInstance()->setBool("ScreenSaverControls", ss_controls->getState()); });
// Render Video Game Name as subtitles
auto ss_info = std::make_shared< OptionListComponent<std::string> >(mWindow, "SHOW GAME INFO", false);
std::vector<std::string> info_type;
info_type.push_back("always");
info_type.push_back("start & end");
info_type.push_back("never");
for(auto it = info_type.begin(); it != info_type.end(); it++)
ss_info->add(*it, *it, Settings::getInstance()->getString("ScreenSaverGameInfo") == *it);
addWithLabel("SHOW GAME INFO ON SCREENSAVER", ss_info);
addSaveFunc([ss_info, this] { Settings::getInstance()->setString("ScreenSaverGameInfo", ss_info->getSelected()); });
#ifndef _RPI_
auto captions_compatibility = std::make_shared<SwitchComponent>(mWindow);
captions_compatibility->setState(Settings::getInstance()->getBool("CaptionsCompatibility"));
addWithLabel("USE COMPATIBLE LOW RESOLUTION FOR CAPTIONS", captions_compatibility);
addSaveFunc([captions_compatibility] { Settings::getInstance()->setBool("CaptionsCompatibility", captions_compatibility->getState()); });
#endif
auto stretch_screensaver = std::make_shared<SwitchComponent>(mWindow);
stretch_screensaver->setState(Settings::getInstance()->getBool("StretchVideoOnScreenSaver"));
addWithLabel("STRETCH VIDEO ON SCREENSAVER", stretch_screensaver);
addSaveFunc([stretch_screensaver] { Settings::getInstance()->setBool("StretchVideoOnScreenSaver", stretch_screensaver->getState()); });
mMenu.addButton("BACK", "go back", [this] { delete this; });
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, Renderer::getScreenHeight() * 0.15f);
}
GuiScreensaverOptions::~GuiScreensaverOptions()
{
save();
}
void GuiScreensaverOptions::save()
{
if(!mSaveFuncs.size())
return;
#ifdef _RPI_
bool startingStatusNotRisky = (Settings::getInstance()->getString("ScreenSaverGameInfo") == "never" || !Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
#endif
for(auto it = mSaveFuncs.begin(); it != mSaveFuncs.end(); it++)
(*it)();
Settings::getInstance()->saveFile();
#ifdef _RPI_
bool endStatusRisky = (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never" && Settings::getInstance()->getBool("ScreenSaverOmxPlayer"));
if (startingStatusNotRisky && endStatusRisky) {
// if before it wasn't risky but now there's a risk of problems, show warning
mWindow->pushGui(new GuiMsgBox(mWindow,
"Using OMX Player and displaying Game Info may result in the video flickering in some TV modes. If that happens, consider:\n\n• Disabling the \"Show Game Info\" option;\n• Disabling \"Overscan\" on the Pi configuration menu might help:\nRetroPie > Raspi-Config > Advanced Options > Overscan > \"No\".\n• Disabling the use of OMX Player for the screensaver.",
"GOT IT!", [] { return; }));
}
#endif
}
bool GuiScreensaverOptions::input(InputConfig* config, Input input)
{
if(config->isMappedTo("b", input) && input.value != 0)
{
delete this;
return true;
}
if(config->isMappedTo("start", input) && input.value != 0)
{
// close everything
Window* window = mWindow;
while(window->peekGui() && window->peekGui() != ViewController::get())
delete window->peekGui();
return true;
}
return GuiComponent::input(config, input);
}
HelpStyle GuiScreensaverOptions::getHelpStyle()
{
HelpStyle style = HelpStyle();
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
return style;
}
std::vector<HelpPrompt> GuiScreensaverOptions::getHelpPrompts()
{
std::vector<HelpPrompt> prompts = mMenu.getHelpPrompts();
prompts.push_back(HelpPrompt("b", "back"));
prompts.push_back(HelpPrompt("start", "close"));
return prompts;
}

View file

@ -0,0 +1,24 @@
#include "GuiComponent.h"
#include "components/MenuComponent.h"
#include "SystemData.h"
// This is just a really simple template for a GUI that calls some save functions when closed.
class GuiScreensaverOptions : public GuiComponent
{
public:
GuiScreensaverOptions(Window* window, const char* title);
virtual ~GuiScreensaverOptions(); // just calls save();
void save();
inline void addRow(const ComponentListRow& row) { mMenu.addRow(row); };
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
bool input(InputConfig* config, Input input) override;
std::vector<HelpPrompt> getHelpPrompts() override;
HelpStyle getHelpStyle() override;
private:
MenuComponent mMenu;
std::vector< std::function<void()> > mSaveFuncs;
};

View file

@ -14,6 +14,7 @@
#include "platform.h"
#include "Log.h"
#include "Window.h"
#include "SystemScreenSaver.h"
#include "EmulationStation.h"
#include "Settings.h"
#include "ScraperCmdLine.h"
@ -222,6 +223,7 @@ int main(int argc, char* argv[])
atexit(&onExit);
Window window;
SystemScreenSaver screensaver(&window);
ViewController::init(&window);
window.pushGui(ViewController::get());

View file

@ -158,6 +158,12 @@ bool SystemView::input(InputConfig* config, Input input)
config->isMappedTo("up", input) ||
config->isMappedTo("down", input))
listInput(0);
if(config->isMappedTo("select", input) && Settings::getInstance()->getBool("ScreenSaverControls"))
{
mWindow->startScreenSaver();
mWindow->renderScreenSaver();
return true;
}
}
return GuiComponent::input(config, input);
@ -348,6 +354,10 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
prompts.push_back(HelpPrompt("left/right", "choose"));
prompts.push_back(HelpPrompt("a", "select"));
prompts.push_back(HelpPrompt("x", "random"));
if (Settings::getInstance()->getBool("ScreenSaverControls"))
prompts.push_back(HelpPrompt("select", "launch screensaver"));
return prompts;
}

View file

@ -19,10 +19,10 @@ public:
virtual const char* getName() const override { return "basic"; }
virtual std::vector<HelpPrompt> getHelpPrompts() override;
virtual void launch(FileData* game) override;
protected:
virtual void populateList(const std::vector<FileData*>& files) override;
virtual void launch(FileData* game) override;
virtual void remove(FileData* game) override;
TextListComponent<FileData*> mList;

View file

@ -14,7 +14,6 @@ public:
virtual const char* getName() const override { return "detailed"; }
protected:
virtual void launch(FileData* game) override;
private:

View file

@ -20,10 +20,10 @@ public:
virtual const char* getName() const override { return "grid"; }
virtual std::vector<HelpPrompt> getHelpPrompts() override;
virtual void launch(FileData* game) override;
protected:
virtual void populateList(const std::vector<FileData*>& files) override;
virtual void launch(FileData* game) override;
ImageGridComponent<FileData*> mGrid;
};

View file

@ -35,6 +35,7 @@ public:
virtual void remove(FileData* game) = 0;
virtual const char* getName() const = 0;
virtual void launch(FileData* game) = 0;
virtual HelpStyle getHelpStyle() override;

View file

@ -23,10 +23,10 @@ public:
virtual void setCursor(FileData*) = 0;
virtual bool input(InputConfig* config, Input input) override;
virtual void launch(FileData* game) = 0;
protected:
virtual void populateList(const std::vector<FileData*>& files) = 0;
virtual void launch(FileData* game) = 0;
TextComponent mHeaderText;
ImageComponent mHeaderImage;

View file

@ -29,11 +29,11 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
// Create the correct type of video window
#ifdef _RPI_
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
mVideo = new VideoPlayerComponent(window);
mVideo = new VideoPlayerComponent(window, "");
else
mVideo = new VideoVlcComponent(window);
mVideo = new VideoVlcComponent(window, getTitlePath());
#else
mVideo = new VideoVlcComponent(window);
mVideo = new VideoVlcComponent(window, getTitlePath());
#endif
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
@ -227,6 +227,8 @@ void VideoGameListView::updateInfoPanel()
{
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
boost::filesystem::remove(getTitlePath().c_str());
bool fadingOut;
if(file == NULL)
{

View file

@ -17,10 +17,9 @@ public:
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
virtual const char* getName() const override { return "video"; }
virtual void launch(FileData* game) override;
protected:
virtual void launch(FileData* game) override;
virtual void update(int deltaTime) override;
private:

View file

@ -87,6 +87,7 @@ public:
virtual void onShow();
virtual void onHide();
virtual void onScreenSaverActivate();
virtual void onScreenSaverDeactivate();
virtual void topWindow(bool isTop);

View file

@ -77,10 +77,22 @@ void Settings::setDefaults()
mStringMap["Scraper"] = "TheGamesDB";
mStringMap["GamelistViewStyle"] = "automatic";
mBoolMap["ScreenSaverControls"] = true;
mStringMap["ScreenSaverGameInfo"] = "never";
mBoolMap["StretchVideoOnScreenSaver"] = false;
// This setting only applies to raspberry pi but set it for all platforms so
// we don't get a warning if we encounter it on a different platform
mBoolMap["VideoOmxPlayer"] = false;
#ifdef _RPI_
// we're defaulting to OMX Player for full screen video on the Pi
mBoolMap["ScreenSaverOmxPlayer"] = true;
#else
mBoolMap["ScreenSaverOmxPlayer"] = false;
#endif
mBoolMap["VideoAudio"] = true;
mBoolMap["CaptionsCompatibility"] = true;
// Audio out device for Video playback using OMX player.
mStringMap["OMXAudioDev"] = "both";

View file

@ -10,7 +10,7 @@
#include "components/ImageComponent.h"
Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCountElapsed(0), mAverageDeltaTime(10),
mAllowSleep(true), mSleeping(false), mTimeSinceLastInput(0)
mAllowSleep(true), mSleeping(false), mTimeSinceLastInput(0), mScreenSaver(NULL), mRenderScreenSaver(false)
{
mHelp = new HelpComponent(this);
mBackgroundOverlay = new ImageComponent(this);
@ -115,26 +115,48 @@ void Window::textInput(const char* text)
void Window::input(InputConfig* config, Input input)
{
if (mRenderScreenSaver)
{
mRenderScreenSaver = false;
// Tell the GUI components the screensaver has stopped
for(auto i = mGuiStack.begin(); i != mGuiStack.end(); i++)
(*i)->onScreenSaverDeactivate();
if (mScreenSaver) {
if(mScreenSaver->isScreenSaverActive() && Settings::getInstance()->getBool("ScreenSaverControls") &&
(Settings::getInstance()->getString("ScreenSaverBehavior") == "random video"))
{
if(mScreenSaver->getCurrentGame() != NULL && (config->isMappedTo("right", input) || config->isMappedTo("start", input) || config->isMappedTo("select", input)))
{
if(config->isMappedTo("right", input) || config->isMappedTo("select", input))
{
if (input.value != 0) {
// handle screensaver control
mScreenSaver->nextVideo();
}
return;
}
else if(config->isMappedTo("start", input))
{
// launch game!
cancelScreenSaver();
mScreenSaver->launchGame();
// to force handling the wake up process
mSleeping = true;
}
}
else if(input.value != 0)
{
return;
}
}
}
if(mSleeping)
{
// wake up
mTimeSinceLastInput = 0;
cancelScreenSaver();
mSleeping = false;
onWake();
return;
}
mTimeSinceLastInput = 0;
cancelScreenSaver();
if(config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_g && SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug"))
{
@ -194,6 +216,10 @@ void Window::update(int deltaTime)
if(peekGui())
peekGui()->update(deltaTime);
// Update the screensaver
if (mScreenSaver)
mScreenSaver->update(deltaTime);
}
void Window::render()
@ -226,18 +252,16 @@ void Window::render()
}
unsigned int screensaverTime = (unsigned int)Settings::getInstance()->getInt("ScreenSaverTime");
if(mTimeSinceLastInput >= screensaverTime && screensaverTime != 0)
startScreenSaver();
// Always call the screensaver render function regardless of whether the screensaver is active
// or not because it may perform a fade on transition
renderScreenSaver();
if(mTimeSinceLastInput >= screensaverTime && screensaverTime != 0)
{
if (!mRenderScreenSaver)
{
for(auto i = mGuiStack.begin(); i != mGuiStack.end(); i++)
(*i)->onScreenSaverActivate();
mRenderScreenSaver = true;
}
renderScreenSaver();
if (!isProcessing() && mAllowSleep)
if (!isProcessing() && mAllowSleep && (!mScreenSaver || mScreenSaver->allowSleep()))
{
// go to sleep
mSleeping = true;
@ -374,9 +398,35 @@ bool Window::isProcessing()
return count_if(mGuiStack.begin(), mGuiStack.end(), [](GuiComponent* c) { return c->isProcessing(); }) > 0;
}
void Window::renderScreenSaver()
{
Renderer::setMatrix(Eigen::Affine3f::Identity());
unsigned char opacity = Settings::getInstance()->getString("ScreenSaverBehavior") == "dim" ? 0xA0 : 0xFF;
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x00000000 | opacity);
}
void Window::startScreenSaver()
{
if (mScreenSaver && !mRenderScreenSaver)
{
// Tell the GUI components the screensaver is starting
for(auto i = mGuiStack.begin(); i != mGuiStack.end(); i++)
(*i)->onScreenSaverActivate();
mScreenSaver->startScreenSaver();
mRenderScreenSaver = true;
}
}
void Window::cancelScreenSaver()
{
if (mScreenSaver && mRenderScreenSaver)
{
mScreenSaver->stopScreenSaver();
mRenderScreenSaver = false;
// Tell the GUI components the screensaver has stopped
for(auto i = mGuiStack.begin(); i != mGuiStack.end(); i++)
(*i)->onScreenSaverDeactivate();
}
}
void Window::renderScreenSaver()
{
if (mScreenSaver)
mScreenSaver->renderScreenSaver();
}

View file

@ -5,12 +5,26 @@
#include "resources/Font.h"
#include "InputManager.h"
class FileData;
class HelpComponent;
class ImageComponent;
class Window
{
public:
class ScreenSaver {
public:
virtual void startScreenSaver() = 0;
virtual void stopScreenSaver() = 0;
virtual void nextVideo() = 0;
virtual void renderScreenSaver() = 0;
virtual bool allowSleep() = 0;
virtual void update(int deltaTime) = 0;
virtual bool isScreenSaverActive() = 0;
virtual FileData* getCurrentGame() = 0;
virtual void launchGame() = 0;
};
Window();
~Window();
@ -38,16 +52,23 @@ public:
void renderHelpPromptsEarly(); // used to render HelpPrompts before a fade
void setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style);
void setScreenSaver(ScreenSaver* screenSaver) { mScreenSaver = screenSaver; }
void startScreenSaver();
void cancelScreenSaver();
void renderScreenSaver();
private:
void onSleep();
void onWake();
// Returns true if at least one component on the stack is processing
bool isProcessing();
void renderScreenSaver();
HelpComponent* mHelp;
ImageComponent* mBackgroundOverlay;
ScreenSaver* mScreenSaver;
bool mRenderScreenSaver;
std::vector<GuiComponent*> mGuiStack;
@ -56,7 +77,6 @@ private:
int mFrameTimeElapsed;
int mFrameCountElapsed;
int mAverageDeltaTime;
bool mRenderScreenSaver;
std::unique_ptr<TextCache> mFrameDataText;

View file

@ -9,6 +9,45 @@
#define FADE_TIME_MS 200
std::string getTitlePath() {
std::string titleFolder = getTitleFolder();
return titleFolder + "last_title.srt";
}
std::string getTitleFolder() {
std::string home = getHomePath();
return home + "/.emulationstation/tmp/";
}
void writeSubtitle(const char* gameName, const char* systemName, bool always)
{
FILE* file = fopen(getTitlePath().c_str(), "w");
if (always) {
fprintf(file, "1\n00:00:01,000 --> 00:00:30,000\n");
}
else
{
fprintf(file, "1\n00:00:01,000 --> 00:00:08,000\n");
}
fprintf(file, "%s\n", gameName);
fprintf(file, "<i>%s</i>\n\n", systemName);
if (!always) {
fprintf(file, "2\n00:00:26,000 --> 00:00:30,000\n");
fprintf(file, "%s\n", gameName);
fprintf(file, "<i>%s</i>\n", systemName);
}
fflush(file);
fclose(file);
file = NULL;
}
void VideoComponent::setScreensaverMode(bool isScreensaver)
{
mScreensaverMode = isScreensaver;
}
VideoComponent::VideoComponent(Window* window) :
GuiComponent(window),
mStaticImage(window),
@ -19,6 +58,7 @@ VideoComponent::VideoComponent(Window* window) :
mShowing(false),
mScreensaverActive(false),
mDisable(false),
mScreensaverMode(false),
mTargetIsMax(false),
mOrigin(0, 0),
mTargetSize(0, 0)
@ -31,12 +71,17 @@ VideoComponent::VideoComponent(Window* window) :
topWindow(false);
}
std::string path = getTitleFolder();
if(!boost::filesystem::exists(path))
boost::filesystem::create_directory(path);
}
VideoComponent::~VideoComponent()
{
// Stop any currently running video
stopVideo();
// Delete subtitle file, if existing
remove(getTitlePath().c_str());
}
void VideoComponent::setOrigin(float originX, float originY)

View file

@ -12,6 +12,10 @@
#include <SDL_mutex.h>
#include <boost/filesystem.hpp>
std::string getTitlePath();
std::string getTitleFolder();
void writeSubtitle(const char* gameName, const char* systemName, bool always);
class VideoComponent : public GuiComponent
{
// Structure that groups together the configuration of the video component
@ -35,6 +39,9 @@ public:
// Configures the component to show the default video
void setDefaultVideo();
// sets whether it's going to render in screensaver mode
void setScreensaverMode(bool isScreensaver);
virtual void onShow() override;
virtual void onHide() override;
virtual void onScreenSaverActivate() override;
@ -107,6 +114,7 @@ protected:
bool mShowing;
bool mDisable;
bool mScreensaverActive;
bool mScreensaverMode;
bool mTargetIsMax;
Configuration mConfig;

View file

@ -1,5 +1,6 @@
#ifdef _RPI_
#include "components/VideoPlayerComponent.h"
#include <boost/algorithm/string/predicate.hpp>
#include "AudioManager.h"
#include "Renderer.h"
#include "ThemeData.h"
@ -11,14 +12,16 @@
#include <sys/stat.h>
#include <fcntl.h>
VideoPlayerComponent::VideoPlayerComponent(Window* window) :
VideoPlayerComponent::VideoPlayerComponent(Window* window, std::string path) :
VideoComponent(window),
mPlayerPid(-1)
mPlayerPid(-1),
subtitlePath(path)
{
}
VideoPlayerComponent::~VideoPlayerComponent()
{
stopVideo();
}
void VideoPlayerComponent::render(const Eigen::Affine3f& parentTrans)
@ -46,7 +49,8 @@ void VideoPlayerComponent::setMaxSize(float width, float height)
void VideoPlayerComponent::startVideo()
{
if (!mIsPlaying) {
if (!mIsPlaying)
{
mVideoWidth = 0;
mVideoHeight = 0;
@ -58,8 +62,11 @@ void VideoPlayerComponent::startVideo()
// Set the video that we are going to be playing so we don't attempt to restart it
mPlayingVideoPath = mVideoPath;
// Disable AudioManager so video can play
AudioManager::getInstance()->deinit();
// Disable AudioManager so video can play, in case we're requesting ALSA
if (boost::starts_with(Settings::getInstance()->getString("OMXAudioDev").c_str(), "alsa"))
{
AudioManager::getInstance()->deinit();
}
// Start the player process
pid_t pid = fork();
@ -88,7 +95,7 @@ void VideoPlayerComponent::startVideo()
// We need to specify the layer of 10000 or above to ensure the video is displayed on top
// of our SDL display
const char* argv[] = { "", "--layer", "10010", "--loop", "--no-osd", "--aspect-mode", "letterbox", "--vol", "0", "-o", "both","--win", buf, "-b", "", "", "", "", NULL };
const char* argv[] = { "", "--layer", "10010", "--loop", "--no-osd", "--aspect-mode", "letterbox", "--vol", "0", "-o", "both","--win", buf, "--no-ghost-box", "", "", "", "", NULL };
// check if we want to mute the audio
if (!Settings::getInstance()->getBool("VideoAudio"))
@ -96,16 +103,43 @@ void VideoPlayerComponent::startVideo()
argv[8] = "-1000000";
}
// if we are rendering a video gamelist
if (!mTargetIsMax)
// test if there's a path for possible subtitles, meaning we're a screensaver video
if (!subtitlePath.empty())
{
argv[6] = "stretch";
// if we are rendering a screensaver
// check if we want to stretch the image
if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver"))
{
argv[6] = "stretch";
}
if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never")
{
// if we have chosen to render subtitles
argv[13] = "--subtitles";
argv[14] = subtitlePath.c_str();
argv[15] = mPlayingVideoPath.c_str();
}
else
{
// if we have chosen NOT to render subtitles in the screensaver
argv[13] = mPlayingVideoPath.c_str();
}
}
else
{
// if we are rendering a video gamelist
if (!mTargetIsMax)
{
argv[6] = "stretch";
}
argv[13] = mPlayingVideoPath.c_str();
}
argv[10] = Settings::getInstance()->getString("OMXAudioDev").c_str();
argv[13] = mPlayingVideoPath.c_str();
//const char* argv[] = args;
const char* env[] = { "LD_LIBRARY_PATH=/opt/vc/libs:/usr/lib/omxplayer", NULL };
// Redirect stdout
@ -141,7 +175,10 @@ void VideoPlayerComponent::stopVideo()
kill(mPlayerPid, SIGKILL);
waitpid(mPlayerPid, &status, WNOHANG);
// Restart AudioManager
AudioManager::getInstance()->init();
if (boost::starts_with(Settings::getInstance()->getString("OMXAudioDev").c_str(), "alsa"))
{
AudioManager::getInstance()->init();
}
mPlayerPid = -1;
}
}

View file

@ -12,7 +12,7 @@ void catch_child(int sig_num);
class VideoPlayerComponent : public VideoComponent
{
public:
VideoPlayerComponent(Window* window);
VideoPlayerComponent(Window* window, std::string path);
virtual ~VideoPlayerComponent();
void render(const Eigen::Affine3f& parentTrans) override;
@ -36,6 +36,7 @@ private:
private:
pid_t mPlayerPid;
std::string subtitlePath;
};
#endif

View file

@ -11,26 +11,26 @@ libvlc_instance_t* VideoVlcComponent::mVLC = NULL;
// VLC prepares to render a video frame.
static void *lock(void *data, void **p_pixels) {
struct VideoContext *c = (struct VideoContext *)data;
SDL_LockMutex(c->mutex);
SDL_LockSurface(c->surface);
struct VideoContext *c = (struct VideoContext *)data;
SDL_LockMutex(c->mutex);
SDL_LockSurface(c->surface);
*p_pixels = c->surface->pixels;
return NULL; // Picture identifier, not needed here.
return NULL; // Picture identifier, not needed here.
}
// VLC just rendered a video frame.
static void unlock(void *data, void *id, void *const *p_pixels) {
struct VideoContext *c = (struct VideoContext *)data;
SDL_UnlockSurface(c->surface);
SDL_UnlockMutex(c->mutex);
struct VideoContext *c = (struct VideoContext *)data;
SDL_UnlockSurface(c->surface);
SDL_UnlockMutex(c->mutex);
}
// VLC wants to display a video frame.
static void display(void *data, void *id) {
//Data to be displayed
//Data to be displayed
}
VideoVlcComponent::VideoVlcComponent(Window* window) :
VideoVlcComponent::VideoVlcComponent(Window* window, std::string subtitles) :
VideoComponent(window),
mMediaPlayer(nullptr)
{
@ -40,11 +40,12 @@ VideoVlcComponent::VideoVlcComponent(Window* window) :
mTexture = TextureResource::get("");
// Make sure VLC has been initialised
setupVLC();
setupVLC(subtitles);
}
VideoVlcComponent::~VideoVlcComponent()
{
stopVideo();
}
void VideoVlcComponent::setResize(float width, float height)
@ -226,13 +227,27 @@ void VideoVlcComponent::freeContext()
}
}
void VideoVlcComponent::setupVLC()
void VideoVlcComponent::setupVLC(std::string subtitles)
{
// If VLC hasn't been initialised yet then do it now
if (!mVLC)
{
const char* args[] = { "--quiet" };
mVLC = libvlc_new(sizeof(args) / sizeof(args[0]), args);
const char** args;
const char* newargs[] = { "--quiet", "--sub-file", subtitles.c_str() };
const char* singleargs[] = { "--quiet" };
int argslen = 0;
if (!subtitles.empty())
{
argslen = sizeof(newargs) / sizeof(newargs[0]);
args = newargs;
}
else
{
argslen = sizeof(singleargs) / sizeof(singleargs[0]);
args = singleargs;
}
mVLC = libvlc_new(argslen, args);
}
}
@ -291,10 +306,31 @@ void VideoVlcComponent::startVideo()
// Make sure we found a valid video track
if ((mVideoWidth > 0) && (mVideoHeight > 0))
{
#ifndef _RPI_
if (mScreensaverMode)
{
if(!Settings::getInstance()->getBool("CaptionsCompatibility")) {
Eigen::Vector2f resizeScale((Renderer::getScreenWidth() / mVideoWidth), (Renderer::getScreenHeight() / mVideoHeight));
if(resizeScale.x() < resizeScale.y())
{
mVideoWidth *= resizeScale.x();
mVideoHeight *= resizeScale.x();
}else{
mVideoWidth *= resizeScale.y();
mVideoHeight *= resizeScale.y();
}
mVideoHeight = round(mVideoHeight);
mVideoWidth = round(mVideoWidth);
}
}
#endif
setupContext();
// Setup the media player
mMediaPlayer = libvlc_media_player_new_from_media(mMedia);
if (!Settings::getInstance()->getBool("VideoAudio"))
{
libvlc_audio_set_mute(mMediaPlayer, 1);

View file

@ -6,6 +6,7 @@
#include "VideoComponent.h"
#include <vlc/vlc.h>
#include <vlc/libvlc_media.h>
#include "resources/TextureResource.h"
struct VideoContext {
@ -26,9 +27,9 @@ class VideoVlcComponent : public VideoComponent
};
public:
static void setupVLC();
static void setupVLC(std::string subtitles);
VideoVlcComponent(Window* window);
VideoVlcComponent(Window* window, std::string subtitles);
virtual ~VideoVlcComponent();
void render(const Eigen::Affine3f& parentTrans) override;

View file

@ -19,6 +19,7 @@
std::string getHomePath();
int runShutdownCommand(); // shut down the system (returns 0 if successful)
int runRestartCommand(); // restart the system (returns 0 if successful)
int runSystemCommand(const std::string& cmd_utf8); // run a utf-8 encoded in the shell (requires wstring conversion on Windows)