mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-03-06 14:27:43 +00:00
Merge pull request #135 from pjft/RetroPie-OMX-Player
Adding OMX Player as experimental option for ES
This commit is contained in:
commit
bc68e0abb0
|
@ -31,8 +31,8 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
// [version]
|
// [version]
|
||||||
|
|
||||||
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
|
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
|
||||||
addEntry("SCRAPER", 0x777777FF, true,
|
addEntry("SCRAPER", 0x777777FF, true,
|
||||||
[this, openScrapeNow] {
|
[this, openScrapeNow] {
|
||||||
auto s = new GuiSettings(mWindow, "SCRAPER");
|
auto s = new GuiSettings(mWindow, "SCRAPER");
|
||||||
|
|
||||||
// scrape from
|
// scrape from
|
||||||
|
@ -65,7 +65,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
addEntry("SOUND SETTINGS", 0x777777FF, true,
|
addEntry("SOUND SETTINGS", 0x777777FF, true,
|
||||||
[this] {
|
[this] {
|
||||||
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
|
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
|
||||||
|
|
||||||
|
@ -74,11 +74,11 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
volume->setValue((float)VolumeControl::getInstance()->getVolume());
|
volume->setValue((float)VolumeControl::getInstance()->getVolume());
|
||||||
s->addWithLabel("SYSTEM VOLUME", volume);
|
s->addWithLabel("SYSTEM VOLUME", volume);
|
||||||
s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)round(volume->getValue())); });
|
s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)round(volume->getValue())); });
|
||||||
|
|
||||||
// disable sounds
|
// disable sounds
|
||||||
auto sounds_enabled = std::make_shared<SwitchComponent>(mWindow);
|
auto sounds_enabled = std::make_shared<SwitchComponent>(mWindow);
|
||||||
sounds_enabled->setState(Settings::getInstance()->getBool("EnableSounds"));
|
sounds_enabled->setState(Settings::getInstance()->getBool("EnableSounds"));
|
||||||
s->addWithLabel("ENABLE SOUNDS", sounds_enabled);
|
s->addWithLabel("ENABLE NAVIGATION SOUNDS", sounds_enabled);
|
||||||
s->addSaveFunc([sounds_enabled] { Settings::getInstance()->setBool("EnableSounds", sounds_enabled->getState()); });
|
s->addSaveFunc([sounds_enabled] { Settings::getInstance()->setBool("EnableSounds", sounds_enabled->getState()); });
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
@ -147,7 +147,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
s->addWithLabel("THEME SET", theme_set);
|
s->addWithLabel("THEME SET", theme_set);
|
||||||
|
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
s->addSaveFunc([window, theme_set]
|
s->addSaveFunc([window, theme_set]
|
||||||
{
|
{
|
||||||
bool needReload = false;
|
bool needReload = false;
|
||||||
if(Settings::getInstance()->getString("ThemeSet") != theme_set->getSelected())
|
if(Settings::getInstance()->getString("ThemeSet") != theme_set->getSelected())
|
||||||
|
@ -174,13 +174,43 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
bool needReload = false;
|
bool needReload = false;
|
||||||
if (Settings::getInstance()->getString("GamelistViewStyle") != gamelist_style->getSelected())
|
if (Settings::getInstance()->getString("GamelistViewStyle") != gamelist_style->getSelected())
|
||||||
needReload = true;
|
needReload = true;
|
||||||
Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected());
|
Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected());
|
||||||
if (needReload)
|
if (needReload)
|
||||||
ViewController::get()->reloadAll();
|
ViewController::get()->reloadAll();
|
||||||
});
|
});
|
||||||
mWindow->pushGui(s);
|
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();
|
||||||
|
});
|
||||||
|
#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()); });
|
||||||
|
|
||||||
|
mWindow->pushGui(s);
|
||||||
|
});
|
||||||
|
|
||||||
addEntry("OTHER SETTINGS", 0x777777FF, true,
|
addEntry("OTHER SETTINGS", 0x777777FF, true,
|
||||||
[this] {
|
[this] {
|
||||||
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
||||||
|
@ -205,7 +235,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
addEntry("CONFIGURE INPUT", 0x777777FF, true,
|
addEntry("CONFIGURE INPUT", 0x777777FF, true,
|
||||||
[this] {
|
[this] {
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
window->pushGui(new GuiMsgBox(window, "ARE YOU SURE YOU WANT TO CONFIGURE INPUT?", "YES",
|
window->pushGui(new GuiMsgBox(window, "ARE YOU SURE YOU WANT TO CONFIGURE INPUT?", "YES",
|
||||||
|
@ -215,10 +245,10 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
addEntry("QUIT", 0x777777FF, true,
|
addEntry("QUIT", 0x777777FF, true,
|
||||||
[this] {
|
[this] {
|
||||||
auto s = new GuiSettings(mWindow, "QUIT");
|
auto s = new GuiSettings(mWindow, "QUIT");
|
||||||
|
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
|
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
|
@ -234,8 +264,8 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
|
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",
|
||||||
[] {
|
[] {
|
||||||
if(quitES("/tmp/es-sysrestart") != 0)
|
if(quitES("/tmp/es-sysrestart") != 0)
|
||||||
LOG(LogWarning) << "Restart terminated with non-zero result!";
|
LOG(LogWarning) << "Restart terminated with non-zero result!";
|
||||||
}, "NO", nullptr));
|
}, "NO", nullptr));
|
||||||
|
@ -245,8 +275,8 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
|
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY SHUTDOWN?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY SHUTDOWN?", "YES",
|
||||||
[] {
|
[] {
|
||||||
if(quitES("/tmp/es-shutdown") != 0)
|
if(quitES("/tmp/es-shutdown") != 0)
|
||||||
LOG(LogWarning) << "Shutdown terminated with non-zero result!";
|
LOG(LogWarning) << "Shutdown terminated with non-zero result!";
|
||||||
}, "NO", nullptr));
|
}, "NO", nullptr));
|
||||||
|
@ -258,8 +288,8 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
{
|
{
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
|
||||||
[] {
|
[] {
|
||||||
SDL_Event ev;
|
SDL_Event ev;
|
||||||
ev.type = SDL_QUIT;
|
ev.type = SDL_QUIT;
|
||||||
SDL_PushEvent(&ev);
|
SDL_PushEvent(&ev);
|
||||||
|
@ -293,7 +323,7 @@ void GuiMenu::onSizeChanged()
|
||||||
void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
|
void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
|
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
|
||||||
|
|
||||||
// populate the list
|
// populate the list
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
|
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
|
||||||
|
@ -303,7 +333,7 @@ void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, con
|
||||||
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
|
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
|
||||||
row.addElement(bracket, false);
|
row.addElement(bracket, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
row.makeAcceptInputHandler(func);
|
row.makeAcceptInputHandler(func);
|
||||||
|
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
#include "animations/LambdaAnimation.h"
|
#include "animations/LambdaAnimation.h"
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#ifdef _RPI_
|
||||||
|
#include "components/VideoPlayerComponent.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
#endif
|
||||||
|
#include "components/VideoVlcComponent.h"
|
||||||
|
|
||||||
VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
BasicGameListView(window, root),
|
BasicGameListView(window, root),
|
||||||
mDescContainer(window), mDescription(window),
|
mDescContainer(window), mDescription(window),
|
||||||
mMarquee(window),
|
mMarquee(window),
|
||||||
mImage(window),
|
mImage(window),
|
||||||
mVideo(window),
|
mVideo(nullptr),
|
||||||
mVideoPlaying(false),
|
mVideoPlaying(false),
|
||||||
|
|
||||||
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
||||||
|
@ -21,6 +26,16 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
|
// Create the correct type of video window
|
||||||
|
#ifdef _RPI_
|
||||||
|
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
||||||
|
mVideo = new VideoPlayerComponent(window);
|
||||||
|
else
|
||||||
|
mVideo = new VideoVlcComponent(window);
|
||||||
|
#else
|
||||||
|
mVideo = new VideoVlcComponent(window);
|
||||||
|
#endif
|
||||||
|
|
||||||
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
||||||
mList.setSize(mSize.x() * (0.50f - padding), mList.getSize().y());
|
mList.setSize(mSize.x() * (0.50f - padding), mList.getSize().y());
|
||||||
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
||||||
|
@ -42,11 +57,11 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
addChild(&mImage);
|
addChild(&mImage);
|
||||||
|
|
||||||
// video
|
// video
|
||||||
mVideo.setOrigin(0.5f, 0.5f);
|
mVideo->setOrigin(0.5f, 0.5f);
|
||||||
mVideo.setPosition(mSize.x() * 0.25f, mSize.y() * 0.4f);
|
mVideo->setPosition(mSize.x() * 0.25f, mSize.y() * 0.4f);
|
||||||
mVideo.setSize(mSize.x() * (0.5f - 2*padding), mSize.y() * 0.4f);
|
mVideo->setSize(mSize.x() * (0.5f - 2*padding), mSize.y() * 0.4f);
|
||||||
mVideo.setDefaultZIndex(30);
|
mVideo->setDefaultZIndex(30);
|
||||||
addChild(&mVideo);
|
addChild(mVideo);
|
||||||
|
|
||||||
// metadata labels + values
|
// metadata labels + values
|
||||||
mLblRating.setText("Rating: ");
|
mLblRating.setText("Rating: ");
|
||||||
|
@ -91,6 +106,7 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
|
|
||||||
VideoGameListView::~VideoGameListView()
|
VideoGameListView::~VideoGameListView()
|
||||||
{
|
{
|
||||||
|
delete mVideo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
|
@ -100,7 +116,7 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mMarquee.applyTheme(theme, getName(), "md_marquee", POSITION | ThemeFlags::SIZE | Z_INDEX);
|
mMarquee.applyTheme(theme, getName(), "md_marquee", POSITION | ThemeFlags::SIZE | Z_INDEX);
|
||||||
mImage.applyTheme(theme, getName(), "md_image", POSITION | ThemeFlags::SIZE | Z_INDEX);
|
mImage.applyTheme(theme, getName(), "md_image", POSITION | ThemeFlags::SIZE | Z_INDEX);
|
||||||
mVideo.applyTheme(theme, getName(), "md_video", POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX);
|
mVideo->applyTheme(theme, getName(), "md_video", POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
|
@ -214,8 +230,8 @@ void VideoGameListView::updateInfoPanel()
|
||||||
bool fadingOut;
|
bool fadingOut;
|
||||||
if(file == NULL)
|
if(file == NULL)
|
||||||
{
|
{
|
||||||
mVideo.setVideo("");
|
mVideo->setVideo("");
|
||||||
mVideo.setImage("");
|
mVideo->setImage("");
|
||||||
mVideoPlaying = false;
|
mVideoPlaying = false;
|
||||||
//mMarquee.setImage("");
|
//mMarquee.setImage("");
|
||||||
//mDescription.setText("");
|
//mDescription.setText("");
|
||||||
|
@ -244,13 +260,13 @@ void VideoGameListView::updateInfoPanel()
|
||||||
thumbnail_path.erase(0, 1);
|
thumbnail_path.erase(0, 1);
|
||||||
thumbnail_path.insert(0, getHomePath());
|
thumbnail_path.insert(0, getHomePath());
|
||||||
}
|
}
|
||||||
if (!mVideo.setVideo(video_path))
|
if (!mVideo->setVideo(video_path))
|
||||||
{
|
{
|
||||||
mVideo.setDefaultVideo();
|
mVideo->setDefaultVideo();
|
||||||
}
|
}
|
||||||
mVideoPlaying = true;
|
mVideoPlaying = true;
|
||||||
|
|
||||||
mVideo.setImage(thumbnail_path);
|
mVideo->setImage(thumbnail_path);
|
||||||
mMarquee.setImage(marquee_path);
|
mMarquee.setImage(marquee_path);
|
||||||
mImage.setImage(thumbnail_path);
|
mImage.setImage(thumbnail_path);
|
||||||
|
|
||||||
|
@ -275,7 +291,7 @@ void VideoGameListView::updateInfoPanel()
|
||||||
|
|
||||||
std::vector<GuiComponent*> comps = getMDValues();
|
std::vector<GuiComponent*> comps = getMDValues();
|
||||||
comps.push_back(&mMarquee);
|
comps.push_back(&mMarquee);
|
||||||
comps.push_back(&mVideo);
|
comps.push_back(mVideo);
|
||||||
comps.push_back(&mDescription);
|
comps.push_back(&mDescription);
|
||||||
comps.push_back(&mImage);
|
comps.push_back(&mImage);
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
|
@ -304,7 +320,7 @@ void VideoGameListView::launch(FileData* game)
|
||||||
{
|
{
|
||||||
Eigen::Vector3f target(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0);
|
Eigen::Vector3f target(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0);
|
||||||
if(mMarquee.hasImage())
|
if(mMarquee.hasImage())
|
||||||
target << mVideo.getCenter().x(), mVideo.getCenter().y(), 0;
|
target << mVideo->getCenter().x(), mVideo->getCenter().y(), 0;
|
||||||
|
|
||||||
ViewController::get()->launch(game, target);
|
ViewController::get()->launch(game, target);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +356,7 @@ std::vector<GuiComponent*> VideoGameListView::getMDValues()
|
||||||
void VideoGameListView::update(int deltaTime)
|
void VideoGameListView::update(int deltaTime)
|
||||||
{
|
{
|
||||||
BasicGameListView::update(deltaTime);
|
BasicGameListView::update(deltaTime);
|
||||||
mVideo.update(deltaTime);
|
mVideo->update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoGameListView::onShow()
|
void VideoGameListView::onShow()
|
||||||
|
|
|
@ -30,7 +30,7 @@ private:
|
||||||
void initMDValues();
|
void initMDValues();
|
||||||
|
|
||||||
ImageComponent mMarquee;
|
ImageComponent mMarquee;
|
||||||
VideoComponent mVideo;
|
VideoComponent* mVideo;
|
||||||
ImageComponent mImage;
|
ImageComponent mImage;
|
||||||
|
|
||||||
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
||||||
|
|
|
@ -43,6 +43,8 @@ set(CORE_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoPlayerComponent.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.h
|
||||||
|
|
||||||
# Guis
|
# Guis
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.h
|
||||||
|
@ -99,6 +101,8 @@ set(CORE_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoComponent.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoPlayerComponent.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/components/VideoVlcComponent.cpp
|
||||||
|
|
||||||
# Guis
|
# Guis
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiDetectDevice.cpp
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "animations/AnimationController.h"
|
#include "animations/AnimationController.h"
|
||||||
#include "ThemeData.h"
|
#include "ThemeData.h"
|
||||||
|
|
||||||
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
|
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
|
||||||
mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity()),
|
mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity()),
|
||||||
mIsProcessing(false)
|
mIsProcessing(false)
|
||||||
{
|
{
|
||||||
|
@ -390,4 +390,20 @@ void GuiComponent::onHide()
|
||||||
getChild(i)->onHide();
|
getChild(i)->onHide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::topWindow(bool isTop)
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < getChildCount(); i++)
|
||||||
|
getChild(i)->topWindow(isTop);
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ public:
|
||||||
void setSize(const Eigen::Vector2f& size);
|
void setSize(const Eigen::Vector2f& size);
|
||||||
void setSize(float w, float h);
|
void setSize(float w, float h);
|
||||||
virtual void onSizeChanged() {};
|
virtual void onSizeChanged() {};
|
||||||
|
|
||||||
float getZIndex() const;
|
float getZIndex() const;
|
||||||
void setZIndex(float zIndex);
|
void setZIndex(float zIndex);
|
||||||
|
|
||||||
|
@ -84,9 +84,12 @@ public:
|
||||||
|
|
||||||
virtual void onFocusGained() {};
|
virtual void onFocusGained() {};
|
||||||
virtual void onFocusLost() {};
|
virtual void onFocusLost() {};
|
||||||
|
|
||||||
virtual void onShow();
|
virtual void onShow();
|
||||||
virtual void onHide();
|
virtual void onHide();
|
||||||
|
virtual void onScreenSaverActivate();
|
||||||
|
virtual void onScreenSaverDeactivate();
|
||||||
|
virtual void topWindow(bool isTop);
|
||||||
|
|
||||||
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
// 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.
|
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||||
|
@ -97,7 +100,7 @@ public:
|
||||||
|
|
||||||
// Called whenever help prompts change.
|
// Called whenever help prompts change.
|
||||||
void updateHelpPrompts();
|
void updateHelpPrompts();
|
||||||
|
|
||||||
virtual HelpStyle getHelpStyle();
|
virtual HelpStyle getHelpStyle();
|
||||||
|
|
||||||
// Returns true if the component is busy doing background processing (e.g. HTTP downloads)
|
// Returns true if the component is busy doing background processing (e.g. HTTP downloads)
|
||||||
|
|
|
@ -47,7 +47,7 @@ void Settings::setDefaults()
|
||||||
mBoolMap["SplashScreen"] = true;
|
mBoolMap["SplashScreen"] = true;
|
||||||
|
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
// don't enable VSync by default on the Pi, since it already
|
// don't enable VSync by default on the Pi, since it already
|
||||||
// has trouble trying to render things at 60fps in certain menus
|
// has trouble trying to render things at 60fps in certain menus
|
||||||
mBoolMap["VSync"] = false;
|
mBoolMap["VSync"] = false;
|
||||||
#else
|
#else
|
||||||
|
@ -76,6 +76,12 @@ void Settings::setDefaults()
|
||||||
mStringMap["ScreenSaverBehavior"] = "dim";
|
mStringMap["ScreenSaverBehavior"] = "dim";
|
||||||
mStringMap["Scraper"] = "TheGamesDB";
|
mStringMap["Scraper"] = "TheGamesDB";
|
||||||
mStringMap["GamelistViewStyle"] = "automatic";
|
mStringMap["GamelistViewStyle"] = "automatic";
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
mBoolMap["VideoAudio"] = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "components/HelpComponent.h"
|
#include "components/HelpComponent.h"
|
||||||
#include "components/ImageComponent.h"
|
#include "components/ImageComponent.h"
|
||||||
|
|
||||||
Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCountElapsed(0), mAverageDeltaTime(10),
|
Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCountElapsed(0), mAverageDeltaTime(10),
|
||||||
mAllowSleep(true), mSleeping(false), mTimeSinceLastInput(0)
|
mAllowSleep(true), mSleeping(false), mTimeSinceLastInput(0)
|
||||||
{
|
{
|
||||||
mHelp = new HelpComponent(this);
|
mHelp = new HelpComponent(this);
|
||||||
|
@ -23,12 +23,17 @@ Window::~Window()
|
||||||
// delete all our GUIs
|
// delete all our GUIs
|
||||||
while(peekGui())
|
while(peekGui())
|
||||||
delete peekGui();
|
delete peekGui();
|
||||||
|
|
||||||
delete mHelp;
|
delete mHelp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::pushGui(GuiComponent* gui)
|
void Window::pushGui(GuiComponent* gui)
|
||||||
{
|
{
|
||||||
|
if (mGuiStack.size() > 0)
|
||||||
|
{
|
||||||
|
auto& top = mGuiStack.back();
|
||||||
|
top->topWindow(false);
|
||||||
|
}
|
||||||
mGuiStack.push_back(gui);
|
mGuiStack.push_back(gui);
|
||||||
gui->updateHelpPrompts();
|
gui->updateHelpPrompts();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +47,10 @@ void Window::removeGui(GuiComponent* gui)
|
||||||
i = mGuiStack.erase(i);
|
i = mGuiStack.erase(i);
|
||||||
|
|
||||||
if(i == mGuiStack.end() && mGuiStack.size()) // we just popped the stack and the stack is not empty
|
if(i == mGuiStack.end() && mGuiStack.size()) // we just popped the stack and the stack is not empty
|
||||||
|
{
|
||||||
mGuiStack.back()->updateHelpPrompts();
|
mGuiStack.back()->updateHelpPrompts();
|
||||||
|
mGuiStack.back()->topWindow(true);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -107,10 +115,20 @@ void Window::textInput(const char* text)
|
||||||
|
|
||||||
void Window::input(InputConfig* config, Input input)
|
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(mSleeping)
|
if(mSleeping)
|
||||||
{
|
{
|
||||||
// wake up
|
// wake up
|
||||||
mTimeSinceLastInput = 0;
|
mTimeSinceLastInput = 0;
|
||||||
|
|
||||||
mSleeping = false;
|
mSleeping = false;
|
||||||
onWake();
|
onWake();
|
||||||
return;
|
return;
|
||||||
|
@ -149,11 +167,11 @@ void Window::update(int deltaTime)
|
||||||
if(mFrameTimeElapsed > 500)
|
if(mFrameTimeElapsed > 500)
|
||||||
{
|
{
|
||||||
mAverageDeltaTime = mFrameTimeElapsed / mFrameCountElapsed;
|
mAverageDeltaTime = mFrameTimeElapsed / mFrameCountElapsed;
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("DrawFramerate"))
|
if(Settings::getInstance()->getBool("DrawFramerate"))
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// fps
|
// fps
|
||||||
ss << std::fixed << std::setprecision(1) << (1000.0f * (float)mFrameCountElapsed / (float)mFrameTimeElapsed) << "fps, ";
|
ss << std::fixed << std::setprecision(1) << (1000.0f * (float)mFrameCountElapsed / (float)mFrameTimeElapsed) << "fps, ";
|
||||||
ss << std::fixed << std::setprecision(2) << ((float)mFrameTimeElapsed / (float)mFrameCountElapsed) << "ms";
|
ss << std::fixed << std::setprecision(2) << ((float)mFrameTimeElapsed / (float)mFrameCountElapsed) << "ms";
|
||||||
|
@ -210,6 +228,13 @@ void Window::render()
|
||||||
unsigned int screensaverTime = (unsigned int)Settings::getInstance()->getInt("ScreenSaverTime");
|
unsigned int screensaverTime = (unsigned int)Settings::getInstance()->getInt("ScreenSaverTime");
|
||||||
if(mTimeSinceLastInput >= screensaverTime && screensaverTime != 0)
|
if(mTimeSinceLastInput >= screensaverTime && screensaverTime != 0)
|
||||||
{
|
{
|
||||||
|
if (!mRenderScreenSaver)
|
||||||
|
{
|
||||||
|
for(auto i = mGuiStack.begin(); i != mGuiStack.end(); i++)
|
||||||
|
(*i)->onScreenSaverActivate();
|
||||||
|
mRenderScreenSaver = true;
|
||||||
|
}
|
||||||
|
|
||||||
renderScreenSaver();
|
renderScreenSaver();
|
||||||
|
|
||||||
if (!isProcessing() && mAllowSleep)
|
if (!isProcessing() && mAllowSleep)
|
||||||
|
@ -250,7 +275,7 @@ void Window::renderLoadingScreen()
|
||||||
|
|
||||||
auto& font = mDefaultFonts.at(1);
|
auto& font = mDefaultFonts.at(1);
|
||||||
TextCache* cache = font->buildTextCache("LOADING...", 0, 0, 0x656565FF);
|
TextCache* cache = font->buildTextCache("LOADING...", 0, 0, 0x656565FF);
|
||||||
trans = trans.translate(Eigen::Vector3f(round((Renderer::getScreenWidth() - cache->metrics.size.x()) / 2.0f),
|
trans = trans.translate(Eigen::Vector3f(round((Renderer::getScreenWidth() - cache->metrics.size.x()) / 2.0f),
|
||||||
round(Renderer::getScreenHeight() * 0.835f), 0.0f));
|
round(Renderer::getScreenHeight() * 0.835f), 0.0f));
|
||||||
Renderer::setMatrix(trans);
|
Renderer::setMatrix(trans);
|
||||||
font->renderTextCache(cache);
|
font->renderTextCache(cache);
|
||||||
|
@ -306,16 +331,16 @@ void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpSt
|
||||||
|
|
||||||
// sort prompts so it goes [dpad_all] [dpad_u/d] [dpad_l/r] [a/b/x/y/l/r] [start/select]
|
// sort prompts so it goes [dpad_all] [dpad_u/d] [dpad_l/r] [a/b/x/y/l/r] [start/select]
|
||||||
std::sort(addPrompts.begin(), addPrompts.end(), [](const HelpPrompt& a, const HelpPrompt& b) -> bool {
|
std::sort(addPrompts.begin(), addPrompts.end(), [](const HelpPrompt& a, const HelpPrompt& b) -> bool {
|
||||||
|
|
||||||
static const char* map[] = {
|
static const char* map[] = {
|
||||||
"up/down/left/right",
|
"up/down/left/right",
|
||||||
"up/down",
|
"up/down",
|
||||||
"left/right",
|
"left/right",
|
||||||
"a", "b", "x", "y", "l", "r",
|
"a", "b", "x", "y", "l", "r",
|
||||||
"start", "select",
|
"start", "select",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int aVal = 0;
|
int aVal = 0;
|
||||||
int bVal = 0;
|
int bVal = 0;
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
void pushGui(GuiComponent* gui);
|
void pushGui(GuiComponent* gui);
|
||||||
void removeGui(GuiComponent* gui);
|
void removeGui(GuiComponent* gui);
|
||||||
GuiComponent* peekGui();
|
GuiComponent* peekGui();
|
||||||
|
inline int getGuiStackSize() { return mGuiStack.size(); }
|
||||||
|
|
||||||
void textInput(const char* text);
|
void textInput(const char* text);
|
||||||
void input(InputConfig* config, Input input);
|
void input(InputConfig* config, Input input);
|
||||||
|
@ -31,7 +32,7 @@ public:
|
||||||
inline bool isSleeping() const { return mSleeping; }
|
inline bool isSleeping() const { return mSleeping; }
|
||||||
bool getAllowSleep();
|
bool getAllowSleep();
|
||||||
void setAllowSleep(bool sleep);
|
void setAllowSleep(bool sleep);
|
||||||
|
|
||||||
void renderLoadingScreen();
|
void renderLoadingScreen();
|
||||||
|
|
||||||
void renderHelpPromptsEarly(); // used to render HelpPrompts before a fade
|
void renderHelpPromptsEarly(); // used to render HelpPrompts before a fade
|
||||||
|
@ -55,6 +56,7 @@ private:
|
||||||
int mFrameTimeElapsed;
|
int mFrameTimeElapsed;
|
||||||
int mFrameCountElapsed;
|
int mFrameCountElapsed;
|
||||||
int mAverageDeltaTime;
|
int mAverageDeltaTime;
|
||||||
|
bool mRenderScreenSaver;
|
||||||
|
|
||||||
std::unique_ptr<TextCache> mFrameDataText;
|
std::unique_ptr<TextCache> mFrameDataText;
|
||||||
|
|
||||||
|
|
|
@ -2,60 +2,35 @@
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "ThemeData.h"
|
#include "ThemeData.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
#include "Window.h"
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FADE_TIME_MS 200
|
#define FADE_TIME_MS 200
|
||||||
|
|
||||||
libvlc_instance_t* VideoComponent::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);
|
|
||||||
*p_pixels = c->surface->pixels;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// VLC wants to display a video frame.
|
|
||||||
static void display(void *data, void *id) {
|
|
||||||
//Data to be displayed
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoComponent::VideoComponent(Window* window) :
|
VideoComponent::VideoComponent(Window* window) :
|
||||||
GuiComponent(window),
|
GuiComponent(window),
|
||||||
mStaticImage(window),
|
mStaticImage(window),
|
||||||
mMediaPlayer(nullptr),
|
|
||||||
mVideoHeight(0),
|
mVideoHeight(0),
|
||||||
mVideoWidth(0),
|
mVideoWidth(0),
|
||||||
mStartDelayed(false),
|
mStartDelayed(false),
|
||||||
mIsPlaying(false),
|
mIsPlaying(false),
|
||||||
mShowing(false),
|
mShowing(false),
|
||||||
|
mScreensaverActive(false),
|
||||||
|
mDisable(false),
|
||||||
mTargetIsMax(false),
|
mTargetIsMax(false),
|
||||||
mOrigin(0, 0),
|
mOrigin(0, 0),
|
||||||
mTargetSize(0, 0)
|
mTargetSize(0, 0)
|
||||||
{
|
{
|
||||||
memset(&mContext, 0, sizeof(mContext));
|
|
||||||
|
|
||||||
// Setup the default configuration
|
// Setup the default configuration
|
||||||
mConfig.showSnapshotDelay = false;
|
mConfig.showSnapshotDelay = false;
|
||||||
mConfig.showSnapshotNoVideo = false;
|
mConfig.showSnapshotNoVideo = false;
|
||||||
mConfig.startDelay = 0;
|
mConfig.startDelay = 0;
|
||||||
|
if (mWindow->getGuiStackSize() > 1) {
|
||||||
|
topWindow(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Get an empty texture for rendering the video
|
|
||||||
mTexture = TextureResource::get("");
|
|
||||||
|
|
||||||
// Make sure VLC has been initialised
|
|
||||||
setupVLC();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoComponent::~VideoComponent()
|
VideoComponent::~VideoComponent()
|
||||||
|
@ -72,89 +47,12 @@ void VideoComponent::setOrigin(float originX, float originY)
|
||||||
mStaticImage.setOrigin(originX, originY);
|
mStaticImage.setOrigin(originX, originY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::setResize(float width, float height)
|
|
||||||
{
|
|
||||||
mTargetSize << width, height;
|
|
||||||
mTargetIsMax = false;
|
|
||||||
mStaticImage.setResize(width, height);
|
|
||||||
resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::setMaxSize(float width, float height)
|
|
||||||
{
|
|
||||||
mTargetSize << width, height;
|
|
||||||
mTargetIsMax = true;
|
|
||||||
mStaticImage.setMaxSize(width, height);
|
|
||||||
resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
Eigen::Vector2f VideoComponent::getCenter() const
|
Eigen::Vector2f VideoComponent::getCenter() const
|
||||||
{
|
{
|
||||||
return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2,
|
return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2,
|
||||||
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
|
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::resize()
|
|
||||||
{
|
|
||||||
if(!mTexture)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Eigen::Vector2f textureSize(mVideoWidth, mVideoHeight);
|
|
||||||
|
|
||||||
if(textureSize.isZero())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// SVG rasterization is determined by height (see SVGResource.cpp), and rasterization is done in terms of pixels
|
|
||||||
// if rounding is off enough in the rasterization step (for images with extreme aspect ratios), it can cause cutoff when the aspect ratio breaks
|
|
||||||
// so, we always make sure the resultant height is an integer to make sure cutoff doesn't happen, and scale width from that
|
|
||||||
// (you'll see this scattered throughout the function)
|
|
||||||
// this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request!
|
|
||||||
|
|
||||||
if(mTargetIsMax)
|
|
||||||
{
|
|
||||||
|
|
||||||
mSize = textureSize;
|
|
||||||
|
|
||||||
Eigen::Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y()));
|
|
||||||
|
|
||||||
if(resizeScale.x() < resizeScale.y())
|
|
||||||
{
|
|
||||||
mSize[0] *= resizeScale.x();
|
|
||||||
mSize[1] *= resizeScale.x();
|
|
||||||
}else{
|
|
||||||
mSize[0] *= resizeScale.y();
|
|
||||||
mSize[1] *= resizeScale.y();
|
|
||||||
}
|
|
||||||
|
|
||||||
// for SVG rasterization, always calculate width from rounded height (see comment above)
|
|
||||||
mSize[1] = round(mSize[1]);
|
|
||||||
mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x();
|
|
||||||
|
|
||||||
}else{
|
|
||||||
// if both components are set, we just stretch
|
|
||||||
// if no components are set, we don't resize at all
|
|
||||||
mSize = mTargetSize.isZero() ? textureSize : mTargetSize;
|
|
||||||
|
|
||||||
// if only one component is set, we resize in a way that maintains aspect ratio
|
|
||||||
// for SVG rasterization, we always calculate width from rounded height (see comment above)
|
|
||||||
if(!mTargetSize.x() && mTargetSize.y())
|
|
||||||
{
|
|
||||||
mSize[1] = round(mTargetSize.y());
|
|
||||||
mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x();
|
|
||||||
}else if(mTargetSize.x() && !mTargetSize.y())
|
|
||||||
{
|
|
||||||
mSize[1] = round((mTargetSize.x() / textureSize.x()) * textureSize.y());
|
|
||||||
mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mSize.y() should already be rounded
|
|
||||||
mTexture->rasterizeAt((int)round(mSize.x()), (int)round(mSize.y()));
|
|
||||||
|
|
||||||
onSizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void VideoComponent::onSizeChanged()
|
void VideoComponent::onSizeChanged()
|
||||||
{
|
{
|
||||||
// Update the embeded static image
|
// Update the embeded static image
|
||||||
|
@ -163,7 +61,7 @@ void VideoComponent::onSizeChanged()
|
||||||
|
|
||||||
bool VideoComponent::setVideo(std::string path)
|
bool VideoComponent::setVideo(std::string path)
|
||||||
{
|
{
|
||||||
// Convert the path into a format VLC can understand
|
// Convert the path into a generic format
|
||||||
boost::filesystem::path fullPath = getCanonicalPath(path);
|
boost::filesystem::path fullPath = getCanonicalPath(path);
|
||||||
fullPath.make_preferred().native();
|
fullPath.make_preferred().native();
|
||||||
|
|
||||||
|
@ -189,8 +87,10 @@ void VideoComponent::setImage(std::string path)
|
||||||
// Check that the image has changed
|
// Check that the image has changed
|
||||||
if (path == mStaticImagePath)
|
if (path == mStaticImagePath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mStaticImage.setImage(path);
|
mStaticImage.setImage(path);
|
||||||
|
// Make the image stretch to fill the video region
|
||||||
|
mStaticImage.setSize(getSize());
|
||||||
mFadeIn = 0.0f;
|
mFadeIn = 0.0f;
|
||||||
mStaticImagePath = path;
|
mStaticImagePath = path;
|
||||||
}
|
}
|
||||||
|
@ -215,83 +115,14 @@ void VideoComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
GuiComponent::renderChildren(trans);
|
GuiComponent::renderChildren(trans);
|
||||||
|
|
||||||
Renderer::setMatrix(trans);
|
Renderer::setMatrix(trans);
|
||||||
|
|
||||||
// Handle the case where the video is delayed
|
// Handle the case where the video is delayed
|
||||||
handleStartDelay();
|
handleStartDelay();
|
||||||
|
|
||||||
// Handle looping of the video
|
// Handle looping of the video
|
||||||
handleLooping();
|
handleLooping();
|
||||||
|
|
||||||
if (mIsPlaying && mContext.valid)
|
if (!mIsPlaying)
|
||||||
{
|
|
||||||
float tex_offs_x = 0.0f;
|
|
||||||
float tex_offs_y = 0.0f;
|
|
||||||
float x2;
|
|
||||||
float y2;
|
|
||||||
|
|
||||||
x = -(float)mSize.x() * mOrigin.x();
|
|
||||||
y = -(float)mSize.y() * mOrigin.y();
|
|
||||||
x2 = x+mSize.x();
|
|
||||||
y2 = y+mSize.y();
|
|
||||||
|
|
||||||
// Define a structure to contain the data for each vertex
|
|
||||||
struct Vertex
|
|
||||||
{
|
|
||||||
Eigen::Vector2f pos;
|
|
||||||
Eigen::Vector2f tex;
|
|
||||||
Eigen::Vector4f colour;
|
|
||||||
} vertices[6];
|
|
||||||
|
|
||||||
// We need two triangles to cover the rectangular area
|
|
||||||
vertices[0].pos[0] = x; vertices[0].pos[1] = y;
|
|
||||||
vertices[1].pos[0] = x; vertices[1].pos[1] = y2;
|
|
||||||
vertices[2].pos[0] = x2; vertices[2].pos[1] = y;
|
|
||||||
|
|
||||||
vertices[3].pos[0] = x2; vertices[3].pos[1] = y;
|
|
||||||
vertices[4].pos[0] = x; vertices[4].pos[1] = y2;
|
|
||||||
vertices[5].pos[0] = x2; vertices[5].pos[1] = y2;
|
|
||||||
|
|
||||||
// Texture coordinates
|
|
||||||
vertices[0].tex[0] = -tex_offs_x; vertices[0].tex[1] = -tex_offs_y;
|
|
||||||
vertices[1].tex[0] = -tex_offs_x; vertices[1].tex[1] = 1.0f + tex_offs_y;
|
|
||||||
vertices[2].tex[0] = 1.0f + tex_offs_x; vertices[2].tex[1] = -tex_offs_y;
|
|
||||||
|
|
||||||
vertices[3].tex[0] = 1.0f + tex_offs_x; vertices[3].tex[1] = -tex_offs_y;
|
|
||||||
vertices[4].tex[0] = -tex_offs_x; vertices[4].tex[1] = 1.0f + tex_offs_y;
|
|
||||||
vertices[5].tex[0] = 1.0f + tex_offs_x; vertices[5].tex[1] = 1.0f + tex_offs_y;
|
|
||||||
|
|
||||||
// Colours - use this to fade the video in and out
|
|
||||||
for (int i = 0; i < (4 * 6); ++i) {
|
|
||||||
if ((i%4) < 3)
|
|
||||||
vertices[i / 4].colour[i % 4] = mFadeIn;
|
|
||||||
else
|
|
||||||
vertices[i / 4].colour[i % 4] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
// Build a texture for the video frame
|
|
||||||
mTexture->initFromPixels((unsigned char*)mContext.surface->pixels, mContext.surface->w, mContext.surface->h);
|
|
||||||
mTexture->bind();
|
|
||||||
|
|
||||||
// Render it
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
glColorPointer(4, GL_FLOAT, sizeof(Vertex), &vertices[0].colour);
|
|
||||||
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].pos);
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].tex);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// This is the case where the video is not currently being displayed. Work out
|
// This is the case where the video is not currently being displayed. Work out
|
||||||
// if we need to display a static image
|
// if we need to display a static image
|
||||||
|
@ -361,38 +192,6 @@ std::vector<HelpPrompt> VideoComponent::getHelpPrompts()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::setupContext()
|
|
||||||
{
|
|
||||||
if (!mContext.valid)
|
|
||||||
{
|
|
||||||
// Create an RGBA surface to render the video into
|
|
||||||
mContext.surface = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)mVideoWidth, (int)mVideoHeight, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
|
|
||||||
mContext.mutex = SDL_CreateMutex();
|
|
||||||
mContext.valid = true;
|
|
||||||
resize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::freeContext()
|
|
||||||
{
|
|
||||||
if (mContext.valid)
|
|
||||||
{
|
|
||||||
SDL_FreeSurface(mContext.surface);
|
|
||||||
SDL_DestroyMutex(mContext.mutex);
|
|
||||||
mContext.valid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::setupVLC()
|
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::handleStartDelay()
|
void VideoComponent::handleStartDelay()
|
||||||
{
|
{
|
||||||
// Only play if any delay has timed out
|
// Only play if any delay has timed out
|
||||||
|
@ -413,74 +212,6 @@ void VideoComponent::handleStartDelay()
|
||||||
|
|
||||||
void VideoComponent::handleLooping()
|
void VideoComponent::handleLooping()
|
||||||
{
|
{
|
||||||
if (mIsPlaying && mMediaPlayer)
|
|
||||||
{
|
|
||||||
libvlc_state_t state = libvlc_media_player_get_state(mMediaPlayer);
|
|
||||||
if (state == libvlc_Ended)
|
|
||||||
{
|
|
||||||
//libvlc_media_player_set_position(mMediaPlayer, 0.0f);
|
|
||||||
libvlc_media_player_set_media(mMediaPlayer, mMedia);
|
|
||||||
libvlc_media_player_play(mMediaPlayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::startVideo()
|
|
||||||
{
|
|
||||||
if (!mIsPlaying) {
|
|
||||||
mVideoWidth = 0;
|
|
||||||
mVideoHeight = 0;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wton;
|
|
||||||
std::string path = wton.to_bytes(mVideoPath.c_str());
|
|
||||||
#else
|
|
||||||
std::string path(mVideoPath.c_str());
|
|
||||||
#endif
|
|
||||||
// Make sure we have a video path
|
|
||||||
if (mVLC && (path.size() > 0))
|
|
||||||
{
|
|
||||||
// Set the video that we are going to be playing so we don't attempt to restart it
|
|
||||||
mPlayingVideoPath = mVideoPath;
|
|
||||||
|
|
||||||
// Open the media
|
|
||||||
mMedia = libvlc_media_new_path(mVLC, path.c_str());
|
|
||||||
if (mMedia)
|
|
||||||
{
|
|
||||||
unsigned track_count;
|
|
||||||
// Get the media metadata so we can find the aspect ratio
|
|
||||||
libvlc_media_parse(mMedia);
|
|
||||||
libvlc_media_track_t** tracks;
|
|
||||||
track_count = libvlc_media_tracks_get(mMedia, &tracks);
|
|
||||||
for (unsigned track = 0; track < track_count; ++track)
|
|
||||||
{
|
|
||||||
if (tracks[track]->i_type == libvlc_track_video)
|
|
||||||
{
|
|
||||||
mVideoWidth = tracks[track]->video->i_width;
|
|
||||||
mVideoHeight = tracks[track]->video->i_height;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
libvlc_media_tracks_release(tracks, track_count);
|
|
||||||
|
|
||||||
// Make sure we found a valid video track
|
|
||||||
if ((mVideoWidth > 0) && (mVideoHeight > 0))
|
|
||||||
{
|
|
||||||
setupContext();
|
|
||||||
|
|
||||||
// Setup the media player
|
|
||||||
mMediaPlayer = libvlc_media_player_new_from_media(mMedia);
|
|
||||||
libvlc_media_player_play(mMediaPlayer);
|
|
||||||
libvlc_video_set_callbacks(mMediaPlayer, lock, unlock, display, (void*)&mContext);
|
|
||||||
libvlc_video_set_format(mMediaPlayer, "RGBA", (int)mVideoWidth, (int)mVideoHeight, (int)mVideoWidth * 4);
|
|
||||||
|
|
||||||
// Update the playing state
|
|
||||||
mIsPlaying = true;
|
|
||||||
mFadeIn = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::startVideoWithDelay()
|
void VideoComponent::startVideoWithDelay()
|
||||||
|
@ -508,21 +239,6 @@ void VideoComponent::startVideoWithDelay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoComponent::stopVideo()
|
|
||||||
{
|
|
||||||
mIsPlaying = false;
|
|
||||||
mStartDelayed = false;
|
|
||||||
// Release the media player so it stops calling back to us
|
|
||||||
if (mMediaPlayer)
|
|
||||||
{
|
|
||||||
libvlc_media_player_stop(mMediaPlayer);
|
|
||||||
libvlc_media_player_release(mMediaPlayer);
|
|
||||||
libvlc_media_release(mMedia);
|
|
||||||
mMediaPlayer = NULL;
|
|
||||||
freeContext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoComponent::update(int deltaTime)
|
void VideoComponent::update(int deltaTime)
|
||||||
{
|
{
|
||||||
manageState();
|
manageState();
|
||||||
|
@ -532,10 +248,10 @@ void VideoComponent::update(int deltaTime)
|
||||||
if (mStartDelayed)
|
if (mStartDelayed)
|
||||||
{
|
{
|
||||||
Uint32 ticks = SDL_GetTicks();
|
Uint32 ticks = SDL_GetTicks();
|
||||||
if (mStartTime > ticks)
|
if (mStartTime > ticks)
|
||||||
{
|
{
|
||||||
Uint32 diff = mStartTime - ticks;
|
Uint32 diff = mStartTime - ticks;
|
||||||
if (diff < FADE_TIME_MS)
|
if (diff < FADE_TIME_MS)
|
||||||
{
|
{
|
||||||
mFadeIn = (float)diff / (float)FADE_TIME_MS;
|
mFadeIn = (float)diff / (float)FADE_TIME_MS;
|
||||||
return;
|
return;
|
||||||
|
@ -554,8 +270,9 @@ void VideoComponent::update(int deltaTime)
|
||||||
|
|
||||||
void VideoComponent::manageState()
|
void VideoComponent::manageState()
|
||||||
{
|
{
|
||||||
// We will only show if the component is on display
|
// We will only show if the component is on display and the screensaver
|
||||||
bool show = mShowing;
|
// is not active
|
||||||
|
bool show = mShowing && !mScreensaverActive && !mDisable;
|
||||||
|
|
||||||
// See if we're already playing
|
// See if we're already playing
|
||||||
if (mIsPlaying)
|
if (mIsPlaying)
|
||||||
|
@ -598,4 +315,20 @@ void VideoComponent::onHide()
|
||||||
manageState();
|
manageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoComponent::onScreenSaverActivate()
|
||||||
|
{
|
||||||
|
mScreensaverActive = true;
|
||||||
|
manageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoComponent::onScreenSaverDeactivate()
|
||||||
|
{
|
||||||
|
mScreensaverActive = false;
|
||||||
|
manageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoComponent::topWindow(bool isTop)
|
||||||
|
{
|
||||||
|
mDisable = !isTop;
|
||||||
|
manageState();
|
||||||
|
}
|
||||||
|
|
|
@ -8,18 +8,10 @@
|
||||||
#include "ImageComponent.h"
|
#include "ImageComponent.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "resources/TextureResource.h"
|
|
||||||
#include <vlc/vlc.h>
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_mutex.h>
|
#include <SDL_mutex.h>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
struct VideoContext {
|
|
||||||
SDL_Surface* surface;
|
|
||||||
SDL_mutex* mutex;
|
|
||||||
bool valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VideoComponent : public GuiComponent
|
class VideoComponent : public GuiComponent
|
||||||
{
|
{
|
||||||
// Structure that groups together the configuration of the video component
|
// Structure that groups together the configuration of the video component
|
||||||
|
@ -32,8 +24,6 @@ class VideoComponent : public GuiComponent
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void setupVLC();
|
|
||||||
|
|
||||||
VideoComponent(Window* window);
|
VideoComponent(Window* window);
|
||||||
virtual ~VideoComponent();
|
virtual ~VideoComponent();
|
||||||
|
|
||||||
|
@ -44,9 +34,12 @@ public:
|
||||||
|
|
||||||
// Configures the component to show the default video
|
// Configures the component to show the default video
|
||||||
void setDefaultVideo();
|
void setDefaultVideo();
|
||||||
|
|
||||||
virtual void onShow() override;
|
virtual void onShow() override;
|
||||||
virtual void onHide() override;
|
virtual void onHide() override;
|
||||||
|
virtual void onScreenSaverActivate() override;
|
||||||
|
virtual void onScreenSaverDeactivate() override;
|
||||||
|
virtual void topWindow(bool isTop) override;
|
||||||
|
|
||||||
//Sets the origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
//Sets the origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
||||||
void setOrigin(float originX, float originY);
|
void setOrigin(float originX, float originY);
|
||||||
|
@ -55,19 +48,6 @@ public:
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
void setOpacity(unsigned char opacity) override;
|
void setOpacity(unsigned char opacity) override;
|
||||||
|
|
||||||
// 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 zero, no resizing.
|
|
||||||
// Can be set before or after a video is loaded.
|
|
||||||
// setMaxSize() and setResize() are mutually exclusive.
|
|
||||||
void setResize(float width, float height);
|
|
||||||
inline void setResize(const Eigen::Vector2f& size) { setResize(size.x(), size.y()); }
|
|
||||||
|
|
||||||
// Resize the video to be as large as possible but fit within a box of this size.
|
|
||||||
// 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);
|
|
||||||
inline void setMaxSize(const Eigen::Vector2f& size) { setMaxSize(size.x(), size.y()); }
|
|
||||||
|
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||||
|
@ -79,35 +59,37 @@ public:
|
||||||
|
|
||||||
virtual void update(int deltaTime);
|
virtual void update(int deltaTime);
|
||||||
|
|
||||||
private:
|
// Resize the video to fit this size. If one axis is zero, scale that axis to maintain aspect ratio.
|
||||||
// Calculates the correct mSize from our resizing information (set by setResize/setMaxSize).
|
// If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing.
|
||||||
// Used internally whenever the resizing parameters or texture change.
|
// Can be set before or after a video is loaded.
|
||||||
void resize();
|
// setMaxSize() and setResize() are mutually exclusive.
|
||||||
|
virtual void setResize(float width, float height) = 0;
|
||||||
|
inline void setResize(const Eigen::Vector2f& size) { setResize(size.x(), size.y()); }
|
||||||
|
|
||||||
|
// Resize the video to be as large as possible but fit within a box of this size.
|
||||||
|
// Can be set before or after a video is loaded.
|
||||||
|
// Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive.
|
||||||
|
virtual void setMaxSize(float width, float height) = 0;
|
||||||
|
inline void setMaxSize(const Eigen::Vector2f& size) { setMaxSize(size.x(), size.y()); }
|
||||||
|
|
||||||
|
private:
|
||||||
// Start the video Immediately
|
// Start the video Immediately
|
||||||
void startVideo();
|
virtual void startVideo() = 0;
|
||||||
|
// Stop the video
|
||||||
|
virtual void stopVideo() { };
|
||||||
|
// Handle looping the video. Must be called periodically
|
||||||
|
virtual void handleLooping();
|
||||||
|
|
||||||
// Start the video after any configured delay
|
// Start the video after any configured delay
|
||||||
void startVideoWithDelay();
|
void startVideoWithDelay();
|
||||||
// Stop the video
|
|
||||||
void stopVideo();
|
|
||||||
|
|
||||||
void setupContext();
|
|
||||||
void freeContext();
|
|
||||||
|
|
||||||
// Handle any delay to the start of playing the video clip. Must be called periodically
|
// Handle any delay to the start of playing the video clip. Must be called periodically
|
||||||
void handleStartDelay();
|
void handleStartDelay();
|
||||||
|
|
||||||
// Handle looping the video. Must be called periodically
|
|
||||||
void handleLooping();
|
|
||||||
|
|
||||||
// Manage the playing state of the component
|
// Manage the playing state of the component
|
||||||
void manageState();
|
void manageState();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
static libvlc_instance_t* mVLC;
|
|
||||||
libvlc_media_t* mMedia;
|
|
||||||
libvlc_media_player_t* mMediaPlayer;
|
|
||||||
VideoContext mContext;
|
|
||||||
unsigned mVideoWidth;
|
unsigned mVideoWidth;
|
||||||
unsigned mVideoHeight;
|
unsigned mVideoHeight;
|
||||||
Eigen::Vector2f mOrigin;
|
Eigen::Vector2f mOrigin;
|
||||||
|
@ -123,6 +105,8 @@ private:
|
||||||
unsigned mStartTime;
|
unsigned mStartTime;
|
||||||
bool mIsPlaying;
|
bool mIsPlaying;
|
||||||
bool mShowing;
|
bool mShowing;
|
||||||
|
bool mDisable;
|
||||||
|
bool mScreensaverActive;
|
||||||
bool mTargetIsMax;
|
bool mTargetIsMax;
|
||||||
|
|
||||||
Configuration mConfig;
|
Configuration mConfig;
|
||||||
|
|
142
es-core/src/components/VideoPlayerComponent.cpp
Normal file
142
es-core/src/components/VideoPlayerComponent.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#ifdef _RPI_
|
||||||
|
#include "components/VideoPlayerComponent.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "ThemeData.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#include <signal.h>
|
||||||
|
#include <wait.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
VideoPlayerComponent::VideoPlayerComponent(Window* window) :
|
||||||
|
VideoComponent(window),
|
||||||
|
mPlayerPid(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoPlayerComponent::~VideoPlayerComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoPlayerComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
|
{
|
||||||
|
VideoComponent::render(parentTrans);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoPlayerComponent::setResize(float width, float height)
|
||||||
|
{
|
||||||
|
setSize(width, height);
|
||||||
|
mTargetSize << width, height;
|
||||||
|
mTargetIsMax = false;
|
||||||
|
mStaticImage.setSize(width, height);
|
||||||
|
onSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoPlayerComponent::setMaxSize(float width, float height)
|
||||||
|
{
|
||||||
|
setSize(width, height);
|
||||||
|
mTargetSize << width, height;
|
||||||
|
mTargetIsMax = true;
|
||||||
|
mStaticImage.setMaxSize(width, height);
|
||||||
|
onSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoPlayerComponent::startVideo()
|
||||||
|
{
|
||||||
|
if (!mIsPlaying) {
|
||||||
|
mVideoWidth = 0;
|
||||||
|
mVideoHeight = 0;
|
||||||
|
|
||||||
|
std::string path(mVideoPath.c_str());
|
||||||
|
|
||||||
|
// Make sure we have a video path
|
||||||
|
if ((path.size() > 0) && (mPlayerPid == -1))
|
||||||
|
{
|
||||||
|
// Set the video that we are going to be playing so we don't attempt to restart it
|
||||||
|
mPlayingVideoPath = mVideoPath;
|
||||||
|
|
||||||
|
// Start the player process
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1)
|
||||||
|
{
|
||||||
|
// Failed
|
||||||
|
mPlayingVideoPath = "";
|
||||||
|
}
|
||||||
|
else if (pid > 0)
|
||||||
|
{
|
||||||
|
mPlayerPid = pid;
|
||||||
|
// Update the playing state
|
||||||
|
signal(SIGCHLD, catch_child);
|
||||||
|
mIsPlaying = true;
|
||||||
|
mFadeIn = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// Find out the pixel position of the video view and build a command line for
|
||||||
|
// omxplayer to position it in the right place
|
||||||
|
char buf[32];
|
||||||
|
float x = mPosition.x() - (mOrigin.x() * mSize.x());
|
||||||
|
float y = mPosition.y() - (mOrigin.y() * mSize.y());
|
||||||
|
sprintf(buf, "%d,%d,%d,%d", (int)x, (int)y, (int)(x + mSize.x()), (int)(y + mSize.y()));
|
||||||
|
// 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", "--win", buf, "-b", "", "", "", "", NULL };
|
||||||
|
|
||||||
|
// check if we want to mute the audio
|
||||||
|
if (!Settings::getInstance()->getBool("VideoAudio"))
|
||||||
|
{
|
||||||
|
argv[8] = "-1000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are rendering a video gamelist
|
||||||
|
if (!mTargetIsMax)
|
||||||
|
{
|
||||||
|
argv[6] = "stretch";
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[11] = mPlayingVideoPath.c_str();
|
||||||
|
|
||||||
|
const char* env[] = { "LD_LIBRARY_PATH=/opt/vc/libs:/usr/lib/omxplayer", NULL };
|
||||||
|
|
||||||
|
// Redirect stdout
|
||||||
|
int fdin = open("/dev/null", O_RDONLY);
|
||||||
|
int fdout = open("/dev/null", O_WRONLY);
|
||||||
|
dup2(fdin, 0);
|
||||||
|
dup2(fdout, 1);
|
||||||
|
// Run the omxplayer binary
|
||||||
|
execve("/usr/bin/omxplayer.bin", (char**)argv, (char**)env);
|
||||||
|
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void catch_child(int sig_num)
|
||||||
|
{
|
||||||
|
/* when we get here, we know there's a zombie child waiting */
|
||||||
|
int child_status;
|
||||||
|
wait(&child_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoPlayerComponent::stopVideo()
|
||||||
|
{
|
||||||
|
mIsPlaying = false;
|
||||||
|
mStartDelayed = false;
|
||||||
|
|
||||||
|
// Stop the player process
|
||||||
|
if (mPlayerPid != -1)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
kill(mPlayerPid, SIGKILL);
|
||||||
|
waitpid(mPlayerPid, &status, WNOHANG);
|
||||||
|
mPlayerPid = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
43
es-core/src/components/VideoPlayerComponent.h
Normal file
43
es-core/src/components/VideoPlayerComponent.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifdef _RPI_
|
||||||
|
#ifndef _VIDEOPLAYERCOMPONENT_H_
|
||||||
|
#define _VIDEOPLAYERCOMPONENT_H_
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include GLHEADER
|
||||||
|
|
||||||
|
#include "components/VideoComponent.h"
|
||||||
|
|
||||||
|
void catch_child(int sig_num);
|
||||||
|
|
||||||
|
class VideoPlayerComponent : public VideoComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VideoPlayerComponent(Window* window);
|
||||||
|
virtual ~VideoPlayerComponent();
|
||||||
|
|
||||||
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
|
// 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 zero, no resizing.
|
||||||
|
// Can be set before or after a video is loaded.
|
||||||
|
// setMaxSize() and setResize() are mutually exclusive.
|
||||||
|
void setResize(float width, float height);
|
||||||
|
|
||||||
|
// Resize the video to be as large as possible but fit within a box of this size.
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Start the video Immediately
|
||||||
|
virtual void startVideo();
|
||||||
|
// Stop the video
|
||||||
|
virtual void stopVideo();
|
||||||
|
|
||||||
|
private:
|
||||||
|
pid_t mPlayerPid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
332
es-core/src/components/VideoVlcComponent.cpp
Normal file
332
es-core/src/components/VideoVlcComponent.cpp
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
#include "components/VideoVlcComponent.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "ThemeData.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <codecvt>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
*p_pixels = c->surface->pixels;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// VLC wants to display a video frame.
|
||||||
|
static void display(void *data, void *id) {
|
||||||
|
//Data to be displayed
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoVlcComponent::VideoVlcComponent(Window* window) :
|
||||||
|
VideoComponent(window),
|
||||||
|
mMediaPlayer(nullptr)
|
||||||
|
{
|
||||||
|
memset(&mContext, 0, sizeof(mContext));
|
||||||
|
|
||||||
|
// Get an empty texture for rendering the video
|
||||||
|
mTexture = TextureResource::get("");
|
||||||
|
|
||||||
|
// Make sure VLC has been initialised
|
||||||
|
setupVLC();
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoVlcComponent::~VideoVlcComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::setResize(float width, float height)
|
||||||
|
{
|
||||||
|
mTargetSize << width, height;
|
||||||
|
mTargetIsMax = false;
|
||||||
|
mStaticImage.setResize(width, height);
|
||||||
|
resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::setMaxSize(float width, float height)
|
||||||
|
{
|
||||||
|
mTargetSize << width, height;
|
||||||
|
mTargetIsMax = true;
|
||||||
|
mStaticImage.setMaxSize(width, height);
|
||||||
|
resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::resize()
|
||||||
|
{
|
||||||
|
if(!mTexture)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Eigen::Vector2f textureSize(mVideoWidth, mVideoHeight);
|
||||||
|
|
||||||
|
if(textureSize.isZero())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// SVG rasterization is determined by height (see SVGResource.cpp), and rasterization is done in terms of pixels
|
||||||
|
// if rounding is off enough in the rasterization step (for images with extreme aspect ratios), it can cause cutoff when the aspect ratio breaks
|
||||||
|
// so, we always make sure the resultant height is an integer to make sure cutoff doesn't happen, and scale width from that
|
||||||
|
// (you'll see this scattered throughout the function)
|
||||||
|
// this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request!
|
||||||
|
|
||||||
|
if(mTargetIsMax)
|
||||||
|
{
|
||||||
|
|
||||||
|
mSize = textureSize;
|
||||||
|
|
||||||
|
Eigen::Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y()));
|
||||||
|
|
||||||
|
if(resizeScale.x() < resizeScale.y())
|
||||||
|
{
|
||||||
|
mSize[0] *= resizeScale.x();
|
||||||
|
mSize[1] *= resizeScale.x();
|
||||||
|
}else{
|
||||||
|
mSize[0] *= resizeScale.y();
|
||||||
|
mSize[1] *= resizeScale.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for SVG rasterization, always calculate width from rounded height (see comment above)
|
||||||
|
mSize[1] = round(mSize[1]);
|
||||||
|
mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x();
|
||||||
|
|
||||||
|
}else{
|
||||||
|
// if both components are set, we just stretch
|
||||||
|
// if no components are set, we don't resize at all
|
||||||
|
mSize = mTargetSize.isZero() ? textureSize : mTargetSize;
|
||||||
|
|
||||||
|
// if only one component is set, we resize in a way that maintains aspect ratio
|
||||||
|
// for SVG rasterization, we always calculate width from rounded height (see comment above)
|
||||||
|
if(!mTargetSize.x() && mTargetSize.y())
|
||||||
|
{
|
||||||
|
mSize[1] = round(mTargetSize.y());
|
||||||
|
mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x();
|
||||||
|
}else if(mTargetSize.x() && !mTargetSize.y())
|
||||||
|
{
|
||||||
|
mSize[1] = round((mTargetSize.x() / textureSize.x()) * textureSize.y());
|
||||||
|
mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mSize.y() should already be rounded
|
||||||
|
mTexture->rasterizeAt((int)round(mSize.x()), (int)round(mSize.y()));
|
||||||
|
|
||||||
|
onSizeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::render(const Eigen::Affine3f& parentTrans)
|
||||||
|
{
|
||||||
|
VideoComponent::render(parentTrans);
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
Eigen::Affine3f trans = parentTrans * getTransform();
|
||||||
|
GuiComponent::renderChildren(trans);
|
||||||
|
|
||||||
|
Renderer::setMatrix(trans);
|
||||||
|
|
||||||
|
if (mIsPlaying && mContext.valid)
|
||||||
|
{
|
||||||
|
float tex_offs_x = 0.0f;
|
||||||
|
float tex_offs_y = 0.0f;
|
||||||
|
float x2;
|
||||||
|
float y2;
|
||||||
|
|
||||||
|
x = -(float)mSize.x() * mOrigin.x();
|
||||||
|
y = -(float)mSize.y() * mOrigin.y();
|
||||||
|
x2 = x+mSize.x();
|
||||||
|
y2 = y+mSize.y();
|
||||||
|
|
||||||
|
// Define a structure to contain the data for each vertex
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
Eigen::Vector2f pos;
|
||||||
|
Eigen::Vector2f tex;
|
||||||
|
Eigen::Vector4f colour;
|
||||||
|
} vertices[6];
|
||||||
|
|
||||||
|
// We need two triangles to cover the rectangular area
|
||||||
|
vertices[0].pos[0] = x; vertices[0].pos[1] = y;
|
||||||
|
vertices[1].pos[0] = x; vertices[1].pos[1] = y2;
|
||||||
|
vertices[2].pos[0] = x2; vertices[2].pos[1] = y;
|
||||||
|
|
||||||
|
vertices[3].pos[0] = x2; vertices[3].pos[1] = y;
|
||||||
|
vertices[4].pos[0] = x; vertices[4].pos[1] = y2;
|
||||||
|
vertices[5].pos[0] = x2; vertices[5].pos[1] = y2;
|
||||||
|
|
||||||
|
// Texture coordinates
|
||||||
|
vertices[0].tex[0] = -tex_offs_x; vertices[0].tex[1] = -tex_offs_y;
|
||||||
|
vertices[1].tex[0] = -tex_offs_x; vertices[1].tex[1] = 1.0f + tex_offs_y;
|
||||||
|
vertices[2].tex[0] = 1.0f + tex_offs_x; vertices[2].tex[1] = -tex_offs_y;
|
||||||
|
|
||||||
|
vertices[3].tex[0] = 1.0f + tex_offs_x; vertices[3].tex[1] = -tex_offs_y;
|
||||||
|
vertices[4].tex[0] = -tex_offs_x; vertices[4].tex[1] = 1.0f + tex_offs_y;
|
||||||
|
vertices[5].tex[0] = 1.0f + tex_offs_x; vertices[5].tex[1] = 1.0f + tex_offs_y;
|
||||||
|
|
||||||
|
// Colours - use this to fade the video in and out
|
||||||
|
for (int i = 0; i < (4 * 6); ++i) {
|
||||||
|
if ((i%4) < 3)
|
||||||
|
vertices[i / 4].colour[i % 4] = mFadeIn;
|
||||||
|
else
|
||||||
|
vertices[i / 4].colour[i % 4] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
// Build a texture for the video frame
|
||||||
|
mTexture->initFromPixels((unsigned char*)mContext.surface->pixels, mContext.surface->w, mContext.surface->h);
|
||||||
|
mTexture->bind();
|
||||||
|
|
||||||
|
// Render it
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
|
glColorPointer(4, GL_FLOAT, sizeof(Vertex), &vertices[0].colour);
|
||||||
|
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].pos);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].tex);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::setupContext()
|
||||||
|
{
|
||||||
|
if (!mContext.valid)
|
||||||
|
{
|
||||||
|
// Create an RGBA surface to render the video into
|
||||||
|
mContext.surface = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)mVideoWidth, (int)mVideoHeight, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
|
||||||
|
mContext.mutex = SDL_CreateMutex();
|
||||||
|
mContext.valid = true;
|
||||||
|
resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::freeContext()
|
||||||
|
{
|
||||||
|
if (mContext.valid)
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(mContext.surface);
|
||||||
|
SDL_DestroyMutex(mContext.mutex);
|
||||||
|
mContext.valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::setupVLC()
|
||||||
|
{
|
||||||
|
// If VLC hasn't been initialised yet then do it now
|
||||||
|
if (!mVLC)
|
||||||
|
{
|
||||||
|
const char* args[] = { "--quiet", "", "", "" };
|
||||||
|
// check if we want to mute the audio
|
||||||
|
|
||||||
|
mVLC = libvlc_new(sizeof(args) / sizeof(args[0]), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::handleLooping()
|
||||||
|
{
|
||||||
|
if (mIsPlaying && mMediaPlayer)
|
||||||
|
{
|
||||||
|
libvlc_state_t state = libvlc_media_player_get_state(mMediaPlayer);
|
||||||
|
if (state == libvlc_Ended)
|
||||||
|
{
|
||||||
|
//libvlc_media_player_set_position(mMediaPlayer, 0.0f);
|
||||||
|
libvlc_media_player_set_media(mMediaPlayer, mMedia);
|
||||||
|
libvlc_media_player_play(mMediaPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::startVideo()
|
||||||
|
{
|
||||||
|
if (!mIsPlaying) {
|
||||||
|
mVideoWidth = 0;
|
||||||
|
mVideoHeight = 0;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wton;
|
||||||
|
std::string path = wton.to_bytes(mVideoPath.c_str());
|
||||||
|
#else
|
||||||
|
std::string path(mVideoPath.c_str());
|
||||||
|
#endif
|
||||||
|
// Make sure we have a video path
|
||||||
|
if (mVLC && (path.size() > 0))
|
||||||
|
{
|
||||||
|
// Set the video that we are going to be playing so we don't attempt to restart it
|
||||||
|
mPlayingVideoPath = mVideoPath;
|
||||||
|
|
||||||
|
// Open the media
|
||||||
|
mMedia = libvlc_media_new_path(mVLC, path.c_str());
|
||||||
|
if (mMedia)
|
||||||
|
{
|
||||||
|
unsigned track_count;
|
||||||
|
// Get the media metadata so we can find the aspect ratio
|
||||||
|
libvlc_media_parse(mMedia);
|
||||||
|
libvlc_media_track_t** tracks;
|
||||||
|
track_count = libvlc_media_tracks_get(mMedia, &tracks);
|
||||||
|
for (unsigned track = 0; track < track_count; ++track)
|
||||||
|
{
|
||||||
|
if (tracks[track]->i_type == libvlc_track_video)
|
||||||
|
{
|
||||||
|
mVideoWidth = tracks[track]->video->i_width;
|
||||||
|
mVideoHeight = tracks[track]->video->i_height;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libvlc_media_tracks_release(tracks, track_count);
|
||||||
|
|
||||||
|
// Make sure we found a valid video track
|
||||||
|
if ((mVideoWidth > 0) && (mVideoHeight > 0))
|
||||||
|
{
|
||||||
|
setupContext();
|
||||||
|
|
||||||
|
// Setup the media player
|
||||||
|
mMediaPlayer = libvlc_media_player_new_from_media(mMedia);
|
||||||
|
if (!Settings::getInstance()->getBool("VideoAudio"))
|
||||||
|
{
|
||||||
|
libvlc_audio_set_mute(mMediaPlayer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
libvlc_media_player_play(mMediaPlayer);
|
||||||
|
libvlc_video_set_callbacks(mMediaPlayer, lock, unlock, display, (void*)&mContext);
|
||||||
|
libvlc_video_set_format(mMediaPlayer, "RGBA", (int)mVideoWidth, (int)mVideoHeight, (int)mVideoWidth * 4);
|
||||||
|
|
||||||
|
// Update the playing state
|
||||||
|
mIsPlaying = true;
|
||||||
|
mFadeIn = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoVlcComponent::stopVideo()
|
||||||
|
{
|
||||||
|
mIsPlaying = false;
|
||||||
|
mStartDelayed = false;
|
||||||
|
// Release the media player so it stops calling back to us
|
||||||
|
if (mMediaPlayer)
|
||||||
|
{
|
||||||
|
libvlc_media_player_stop(mMediaPlayer);
|
||||||
|
libvlc_media_player_release(mMediaPlayer);
|
||||||
|
libvlc_media_release(mMedia);
|
||||||
|
mMediaPlayer = NULL;
|
||||||
|
freeContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
70
es-core/src/components/VideoVlcComponent.h
Normal file
70
es-core/src/components/VideoVlcComponent.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef _VIDEOVLCCOMPONENT_H_
|
||||||
|
#define _VIDEOVLCCOMPONENT_H_
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include GLHEADER
|
||||||
|
|
||||||
|
#include "VideoComponent.h"
|
||||||
|
#include <vlc/vlc.h>
|
||||||
|
#include "resources/TextureResource.h"
|
||||||
|
|
||||||
|
struct VideoContext {
|
||||||
|
SDL_Surface* surface;
|
||||||
|
SDL_mutex* mutex;
|
||||||
|
bool valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VideoVlcComponent : public VideoComponent
|
||||||
|
{
|
||||||
|
// Structure that groups together the configuration of the video component
|
||||||
|
struct Configuration
|
||||||
|
{
|
||||||
|
unsigned startDelay;
|
||||||
|
bool showSnapshotNoVideo;
|
||||||
|
bool showSnapshotDelay;
|
||||||
|
std::string defaultVideoPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void setupVLC();
|
||||||
|
|
||||||
|
VideoVlcComponent(Window* window);
|
||||||
|
virtual ~VideoVlcComponent();
|
||||||
|
|
||||||
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
|
|
||||||
|
// 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 zero, no resizing.
|
||||||
|
// Can be set before or after a video is loaded.
|
||||||
|
// setMaxSize() and setResize() are mutually exclusive.
|
||||||
|
void setResize(float width, float height);
|
||||||
|
|
||||||
|
// Resize the video to be as large as possible but fit within a box of this size.
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Calculates the correct mSize from our resizing information (set by setResize/setMaxSize).
|
||||||
|
// Used internally whenever the resizing parameters or texture change.
|
||||||
|
void resize();
|
||||||
|
// Start the video Immediately
|
||||||
|
virtual void startVideo();
|
||||||
|
// Stop the video
|
||||||
|
virtual void stopVideo();
|
||||||
|
// Handle looping the video. Must be called periodically
|
||||||
|
virtual void handleLooping();
|
||||||
|
|
||||||
|
void setupContext();
|
||||||
|
void freeContext();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static libvlc_instance_t* mVLC;
|
||||||
|
libvlc_media_t* mMedia;
|
||||||
|
libvlc_media_player_t* mMediaPlayer;
|
||||||
|
VideoContext mContext;
|
||||||
|
std::shared_ptr<TextureResource> mTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue