From bbb5575334d654c9b7eeb10f08d3c3a15c5e0f78 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Mon, 16 Nov 2020 23:34:08 +0100 Subject: [PATCH] Added black areas around videos with non-standard aspect ratios. --- NEWS.md | 1 + es-core/src/components/VideoComponent.cpp | 62 ++++++++------ es-core/src/components/VideoComponent.h | 3 + es-core/src/components/VideoVlcComponent.cpp | 90 +++++++++++++++++--- es-core/src/components/VideoVlcComponent.h | 1 + themes/rbsimple-DE/theme.xml | 2 +- 6 files changed, 124 insertions(+), 35 deletions(-) diff --git a/NEWS.md b/NEWS.md index 75d1c839e..d8706e50d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 * 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 +* 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 * 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 diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 15db59db8..dc800f934 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -16,7 +16,7 @@ #include -#define SCREENSAVER_FADE_IN_TIME 800 +#define SCREENSAVER_FADE_IN_TIME 1200 void VideoComponent::setScreensaverMode(bool isScreensaver) { @@ -24,24 +24,27 @@ void VideoComponent::setScreensaverMode(bool isScreensaver) } VideoComponent::VideoComponent( - Window* window) - : GuiComponent(window), - mWindow(window), - mStaticImage(window), - mVideoHeight(0), - mVideoWidth(0), - mStartDelayed(false), - mIsPlaying(false), - mPause(false), - mShowing(false), - mDisable(false), - mScreensaverActive(false), - mScreensaverMode(false), - mGameLaunched(false), - mBlockPlayer(false), - mTargetIsMax(false), - mFadeIn(1.0), - mTargetSize(0, 0) + Window* window) + : GuiComponent(window), + mWindow(window), + mStaticImage(window), + mVideoHeight(0), + mVideoWidth(0), + mStartDelayed(false), + mIsPlaying(false), + mIsActuallyPlaying(false), + mPause(false), + mShowing(false), + mDisable(false), + mScreensaverActive(false), + mScreensaverMode(false), + mGameLaunched(false), + mBlockPlayer(false), + mTargetIsMax(false), + mFadeIn(1.0), + mTargetSize(0, 0), + mVideoAreaPos(0, 0), + mVideoAreaSize(0, 0) { // Setup the default configuration. mConfig.showSnapshotDelay = false; @@ -169,10 +172,19 @@ void VideoComponent::applyTheme(const std::shared_ptr& theme, const s static_cast(Renderer::getScreenHeight())); if (properties & ThemeFlags::SIZE) { - if (elem->has("size")) + if (elem->has("size")) { setResize(elem->get("size") * scale); - else if (elem->has("maxSize")) + mVideoAreaSize = elem->get("size") * scale; + } + else if (elem->has("maxSize")) { setMaxSize(elem->get("maxSize") * scale); + mVideoAreaSize = elem->get("maxSize") * scale; + } + } + + if (properties & ThemeFlags::POSITION) { + if (elem->has("pos")) + mVideoAreaPos = elem->get("pos") * scale; } if (elem->has("default")) @@ -258,11 +270,13 @@ void VideoComponent::update(int deltaTime) manageState(); - // This is only used to fade in the screensaver, fade-in of the static image is - // handled using a lambda animation in VideoGameListView. - if (mFadeIn < 1.0f) + // Fade in videos, which is handled a bit differently depending on whether it's the + // video screensaver that is running, or if it's the video in the gamelist. + if (mScreensaverMode && mFadeIn < 1.0f) mFadeIn = Math::clamp(mFadeIn + (deltaTime / static_cast(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); } diff --git a/es-core/src/components/VideoComponent.h b/es-core/src/components/VideoComponent.h index 2de7bf0ac..cd6f9fbce 100644 --- a/es-core/src/components/VideoComponent.h +++ b/es-core/src/components/VideoComponent.h @@ -104,6 +104,8 @@ protected: unsigned mVideoWidth; unsigned mVideoHeight; Vector2f mTargetSize; + Vector2f mVideoAreaPos; + Vector2f mVideoAreaSize; std::shared_ptr mTexture; std::string mStaticImagePath; ImageComponent mStaticImage; @@ -113,6 +115,7 @@ protected: unsigned mStartTime; bool mStartDelayed; bool mIsPlaying; + bool mIsActuallyPlaying; bool mPause; bool mShowing; bool mDisable; diff --git a/es-core/src/components/VideoVlcComponent.cpp b/es-core/src/components/VideoVlcComponent.cpp index 826b0b337..055728186 100644 --- a/es-core/src/components/VideoVlcComponent.cpp +++ b/es-core/src/components/VideoVlcComponent.cpp @@ -150,14 +150,40 @@ void VideoVlcComponent::render(const Transform4x4f& parentTrans) VideoComponent::render(parentTrans); Transform4x4f trans = parentTrans * getTransform(); GuiComponent::renderChildren(trans); - Renderer::setMatrix(trans); - if (mIsPlaying && mContext.valid) { - // This fade in is only used by the video screensaver. - const unsigned int fadeIn = (unsigned int)(Math::clamp(mFadeIn, 0.0f, 1.0f) * 255.0f); - const unsigned int color = - Renderer::convertColor((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255); + // Check the actual VLC state, i.e. if the video is really playing rather than + // still being opened. + if (mMediaPlayer && mIsPlaying && !mIsActuallyPlaying) { + libvlc_state_t state; + 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::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[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) // Render scanlines if this option is enabled. However, if this is the video - // screensaver, then skip this as screensaver scanline rendering is handled from - // Window.cpp as a postprocessing step. + // screensaver, then skip this as screensaver scanline rendering is handled in + // SystemScreenSaver as a postprocessing step. if (!mScreensaverMode && Settings::getInstance()->getBool("GamelistVideoScanlines")) vertices[0].shaders = Renderer::SHADER_SCANLINES; #endif // Render it. + Renderer::setMatrix(trans); Renderer::drawTriangleStrips(&vertices[0], 4, trans); } else { @@ -292,8 +319,8 @@ void VideoVlcComponent::startVideo() libvlc_event_t vlcEvent; // Asynchronous media parsing. - libvlc_event_attach(libvlc_media_event_manager( - mMedia), libvlc_MediaParsedChanged, VlcMediaParseCallback, 0); + libvlc_event_attach(libvlc_media_event_manager(mMedia), + libvlc_MediaParsedChanged, VlcMediaParseCallback, 0); parseResult = libvlc_media_parse_with_options(mMedia, libvlc_media_parse_local, -1); if (!parseResult) { @@ -340,6 +367,48 @@ void VideoVlcComponent::startVideo() mIsPlaying = true; 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() { mIsPlaying = false; + mIsActuallyPlaying = false; mStartDelayed = false; mPause = false; // Release the media player so it stops calling back to us. diff --git a/es-core/src/components/VideoVlcComponent.h b/es-core/src/components/VideoVlcComponent.h index b86b097d1..6df1bed4b 100644 --- a/es-core/src/components/VideoVlcComponent.h +++ b/es-core/src/components/VideoVlcComponent.h @@ -79,6 +79,7 @@ private: libvlc_media_player_t* mMediaPlayer; VideoContext mContext; std::shared_ptr mTexture; + std::vector mVideoRectangleCoords; }; #endif // ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H diff --git a/themes/rbsimple-DE/theme.xml b/themes/rbsimple-DE/theme.xml index ea723710b..4e2971208 100644 --- a/themes/rbsimple-DE/theme.xml +++ b/themes/rbsimple-DE/theme.xml @@ -284,7 +284,7 @@ based on: 'recalbox-multi' by the Recalbox community