Added black areas around videos with non-standard aspect ratios.

This commit is contained in:
Leon Styhre 2020-11-16 23:34:08 +01:00
parent f334eb7037
commit bbb5575334
6 changed files with 124 additions and 35 deletions

View file

@ -49,6 +49,7 @@ Many bugs have been fixed, and numerous features that were only partially implem
* Improved input device configuration, and default keyboard mappings are now applied if the keyboard has not been configured by the user * Improved input device configuration, and default keyboard mappings are now applied if the keyboard has not been configured by the user
* GUI-configurable option to sort favorite games above non-favorite games (favorites marked with stars) * GUI-configurable option to sort favorite games above non-favorite games (favorites marked with stars)
* GUI-configurable option to sort folders on top of the gamelists * GUI-configurable option to sort folders on top of the gamelists
* Added the ability to display a black area around videos with non-standard aspect ratios, for example vertical shooters
* Added a gamelist info text field displaying the game count, any applied filters as well as an icon if a folder has been entered * Added a gamelist info text field displaying the game count, any applied filters as well as an icon if a folder has been entered
* Expanded the gamelist filter functionality to include completed and broken games as well as the ability to filter on game names (via free text entry) * Expanded the gamelist filter functionality to include completed and broken games as well as the ability to filter on game names (via free text entry)
* Expanded the metadata for folders and made it possible to mark them as favorites * Expanded the metadata for folders and made it possible to mark them as favorites

View file

@ -16,7 +16,7 @@
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
#define SCREENSAVER_FADE_IN_TIME 800 #define SCREENSAVER_FADE_IN_TIME 1200
void VideoComponent::setScreensaverMode(bool isScreensaver) void VideoComponent::setScreensaverMode(bool isScreensaver)
{ {
@ -24,24 +24,27 @@ void VideoComponent::setScreensaverMode(bool isScreensaver)
} }
VideoComponent::VideoComponent( VideoComponent::VideoComponent(
Window* window) Window* window)
: GuiComponent(window), : GuiComponent(window),
mWindow(window), mWindow(window),
mStaticImage(window), mStaticImage(window),
mVideoHeight(0), mVideoHeight(0),
mVideoWidth(0), mVideoWidth(0),
mStartDelayed(false), mStartDelayed(false),
mIsPlaying(false), mIsPlaying(false),
mPause(false), mIsActuallyPlaying(false),
mShowing(false), mPause(false),
mDisable(false), mShowing(false),
mScreensaverActive(false), mDisable(false),
mScreensaverMode(false), mScreensaverActive(false),
mGameLaunched(false), mScreensaverMode(false),
mBlockPlayer(false), mGameLaunched(false),
mTargetIsMax(false), mBlockPlayer(false),
mFadeIn(1.0), mTargetIsMax(false),
mTargetSize(0, 0) mFadeIn(1.0),
mTargetSize(0, 0),
mVideoAreaPos(0, 0),
mVideoAreaSize(0, 0)
{ {
// Setup the default configuration. // Setup the default configuration.
mConfig.showSnapshotDelay = false; mConfig.showSnapshotDelay = false;
@ -169,10 +172,19 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const s
static_cast<float>(Renderer::getScreenHeight())); static_cast<float>(Renderer::getScreenHeight()));
if (properties & ThemeFlags::SIZE) { if (properties & ThemeFlags::SIZE) {
if (elem->has("size")) if (elem->has("size")) {
setResize(elem->get<Vector2f>("size") * scale); setResize(elem->get<Vector2f>("size") * scale);
else if (elem->has("maxSize")) mVideoAreaSize = elem->get<Vector2f>("size") * scale;
}
else if (elem->has("maxSize")) {
setMaxSize(elem->get<Vector2f>("maxSize") * scale); setMaxSize(elem->get<Vector2f>("maxSize") * scale);
mVideoAreaSize = elem->get<Vector2f>("maxSize") * scale;
}
}
if (properties & ThemeFlags::POSITION) {
if (elem->has("pos"))
mVideoAreaPos = elem->get<Vector2f>("pos") * scale;
} }
if (elem->has("default")) if (elem->has("default"))
@ -258,11 +270,13 @@ void VideoComponent::update(int deltaTime)
manageState(); manageState();
// This is only used to fade in the screensaver, fade-in of the static image is // Fade in videos, which is handled a bit differently depending on whether it's the
// handled using a lambda animation in VideoGameListView. // video screensaver that is running, or if it's the video in the gamelist.
if (mFadeIn < 1.0f) if (mScreensaverMode && mFadeIn < 1.0f)
mFadeIn = Math::clamp(mFadeIn + (deltaTime / mFadeIn = Math::clamp(mFadeIn + (deltaTime /
static_cast<float>(SCREENSAVER_FADE_IN_TIME)), 0.0, 1.0); static_cast<float>(SCREENSAVER_FADE_IN_TIME)), 0.0, 1.0);
else if (mFadeIn < 1.0f)
mFadeIn = Math::clamp(mFadeIn + 0.01, 0.0f, 1.0f);
GuiComponent::update(deltaTime); GuiComponent::update(deltaTime);
} }

View file

@ -104,6 +104,8 @@ protected:
unsigned mVideoWidth; unsigned mVideoWidth;
unsigned mVideoHeight; unsigned mVideoHeight;
Vector2f mTargetSize; Vector2f mTargetSize;
Vector2f mVideoAreaPos;
Vector2f mVideoAreaSize;
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
std::string mStaticImagePath; std::string mStaticImagePath;
ImageComponent mStaticImage; ImageComponent mStaticImage;
@ -113,6 +115,7 @@ protected:
unsigned mStartTime; unsigned mStartTime;
bool mStartDelayed; bool mStartDelayed;
bool mIsPlaying; bool mIsPlaying;
bool mIsActuallyPlaying;
bool mPause; bool mPause;
bool mShowing; bool mShowing;
bool mDisable; bool mDisable;

View file

@ -150,14 +150,40 @@ void VideoVlcComponent::render(const Transform4x4f& parentTrans)
VideoComponent::render(parentTrans); VideoComponent::render(parentTrans);
Transform4x4f trans = parentTrans * getTransform(); Transform4x4f trans = parentTrans * getTransform();
GuiComponent::renderChildren(trans); GuiComponent::renderChildren(trans);
Renderer::setMatrix(trans);
if (mIsPlaying && mContext.valid) { // Check the actual VLC state, i.e. if the video is really playing rather than
// This fade in is only used by the video screensaver. // still being opened.
const unsigned int fadeIn = (unsigned int)(Math::clamp(mFadeIn, 0.0f, 1.0f) * 255.0f); if (mMediaPlayer && mIsPlaying && !mIsActuallyPlaying) {
const unsigned int color = libvlc_state_t state;
Renderer::convertColor((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255); state = libvlc_media_player_get_state(mMediaPlayer);
if (state == libvlc_Playing)
mIsActuallyPlaying = true;
}
if (!mIsActuallyPlaying && !mStaticImage.isVisible())
mStaticImage.setVisible(true);
if (mIsPlaying && mContext.valid && mIsActuallyPlaying) {
unsigned int color;
if (mFadeIn < 1) {
const unsigned int fadeIn = mFadeIn * 255.0f;
color = Renderer::convertColor((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255);
}
else {
color = 0xFFFFFFFF;
}
Renderer::Vertex vertices[4]; Renderer::Vertex vertices[4];
Renderer::setMatrix(parentTrans);
// Render the black rectangle behind the video.
if (mVideoRectangleCoords.size() == 4) {
Renderer::drawRect(mVideoRectangleCoords[0], mVideoRectangleCoords[1],
mVideoRectangleCoords[2], mVideoRectangleCoords[3],
0x000000FF, 0x000000FF);
if (mStaticImage.isVisible())
mStaticImage.setVisible(false);
}
vertices[0] = { { 0.0f , 0.0f }, { 0.0f, 0.0f }, color }; vertices[0] = { { 0.0f , 0.0f }, { 0.0f, 0.0f }, color };
vertices[1] = { { 0.0f , mSize.y() }, { 0.0f, 1.0f }, color }; vertices[1] = { { 0.0f , mSize.y() }, { 0.0f, 1.0f }, color };
@ -175,13 +201,14 @@ void VideoVlcComponent::render(const Transform4x4f& parentTrans)
#if defined(USE_OPENGL_21) #if defined(USE_OPENGL_21)
// Render scanlines if this option is enabled. However, if this is the video // Render scanlines if this option is enabled. However, if this is the video
// screensaver, then skip this as screensaver scanline rendering is handled from // screensaver, then skip this as screensaver scanline rendering is handled in
// Window.cpp as a postprocessing step. // SystemScreenSaver as a postprocessing step.
if (!mScreensaverMode && Settings::getInstance()->getBool("GamelistVideoScanlines")) if (!mScreensaverMode && Settings::getInstance()->getBool("GamelistVideoScanlines"))
vertices[0].shaders = Renderer::SHADER_SCANLINES; vertices[0].shaders = Renderer::SHADER_SCANLINES;
#endif #endif
// Render it. // Render it.
Renderer::setMatrix(trans);
Renderer::drawTriangleStrips(&vertices[0], 4, trans); Renderer::drawTriangleStrips(&vertices[0], 4, trans);
} }
else { else {
@ -292,8 +319,8 @@ void VideoVlcComponent::startVideo()
libvlc_event_t vlcEvent; libvlc_event_t vlcEvent;
// Asynchronous media parsing. // Asynchronous media parsing.
libvlc_event_attach(libvlc_media_event_manager( libvlc_event_attach(libvlc_media_event_manager(mMedia),
mMedia), libvlc_MediaParsedChanged, VlcMediaParseCallback, 0); libvlc_MediaParsedChanged, VlcMediaParseCallback, 0);
parseResult = libvlc_media_parse_with_options(mMedia, libvlc_media_parse_local, -1); parseResult = libvlc_media_parse_with_options(mMedia, libvlc_media_parse_local, -1);
if (!parseResult) { if (!parseResult) {
@ -340,6 +367,48 @@ void VideoVlcComponent::startVideo()
mIsPlaying = true; mIsPlaying = true;
mFadeIn = 0.0f; mFadeIn = 0.0f;
} }
if (mIsPlaying) {
// Create the position and size for the black rectangle that will be
// rendered behind videos that are not filling the whole md_video area.
if (mVideoAreaPos != 0 && mVideoAreaSize != 0) {
mVideoRectangleCoords.clear();
float rectHeight;
float rectWidth;
// Video is in landscape orientation.
if (mSize.x() > mSize.y()) {
// Checking the Y size should not normally be required as landscape
// format should mean the height can't be higher than the max size
// defined by the theme. But as the height in mSize is provided by
// libVLC in integer format and then scaled, there could be rounding
// errors that make the video height slightly higher than allowed.
// It's only a pixel or so, but it's still visible for some videos.
if (mSize.y() < mVideoAreaSize.y() &&
mSize.y() / mVideoAreaSize.y() < 0.97)
rectHeight = mVideoAreaSize.y();
else
rectHeight = mSize.y();
// Don't add a black border that is too narrow, that's what the
// 0.85 constant takes care of.
if (mSize.x() < mVideoAreaSize.x() &&
mSize.x() / mVideoAreaSize.x() < 0.85)
rectWidth = mVideoAreaSize.x();
else
rectWidth = mSize.x();
}
// Video is in portrait orientation (or completely square).
else {
rectWidth = mVideoAreaSize.x();
rectHeight = mSize.y();
}
// Populate the rectangle coordinates to be used in render().
mVideoRectangleCoords.push_back(mVideoAreaPos.x() -
rectWidth * mOrigin.x());
mVideoRectangleCoords.push_back(mVideoAreaPos.y() -
rectHeight * mOrigin.y());
mVideoRectangleCoords.push_back(rectWidth);
mVideoRectangleCoords.push_back(rectHeight);
}
}
} }
} }
} }
@ -348,6 +417,7 @@ void VideoVlcComponent::startVideo()
void VideoVlcComponent::stopVideo() void VideoVlcComponent::stopVideo()
{ {
mIsPlaying = false; mIsPlaying = false;
mIsActuallyPlaying = false;
mStartDelayed = false; mStartDelayed = false;
mPause = false; mPause = false;
// Release the media player so it stops calling back to us. // Release the media player so it stops calling back to us.

View file

@ -79,6 +79,7 @@ private:
libvlc_media_player_t* mMediaPlayer; libvlc_media_player_t* mMediaPlayer;
VideoContext mContext; VideoContext mContext;
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
std::vector<float> mVideoRectangleCoords;
}; };
#endif // ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H #endif // ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H

View file

@ -284,7 +284,7 @@ based on: 'recalbox-multi' by the Recalbox community
<video name="md_video"> <video name="md_video">
<origin>0.5 0.5</origin> <origin>0.5 0.5</origin>
<pos>0.63 0.45</pos> <pos>0.63 0.45</pos>
<maxSize>0.360 0.424</maxSize> <maxSize>0.356 0.424</maxSize>
<delay>1.7</delay> <delay>1.7</delay>
<showSnapshotNoVideo>true</showSnapshotNoVideo> <showSnapshotNoVideo>true</showSnapshotNoVideo>
<showSnapshotDelay>true</showSnapshotDelay> <showSnapshotDelay>true</showSnapshotDelay>