mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Merge branch 'master' into 575-theme-add-a-modern-clean-switch-like-theme-as-an-official-theme-in-es-de-to-choose-from
This commit is contained in:
commit
b3e42a4a17
|
@ -35,6 +35,7 @@ option(RPI "Set to ON to enable Raspberry Pi specific build" ${RPI})
|
|||
option(CEC "Set to ON to enable CEC" ${CEC})
|
||||
option(VLC_PLAYER "Set to ON to build the VLC-based video player" ${VLC_PLAYER})
|
||||
option(CLANG_TIDY "Set to ON to build using the clang-tidy static analyzer" ${CLANG_TIDY})
|
||||
option(VIDEO_HW_DECODING "Set to OFF to disable FFmpeg HW decoding" ON)
|
||||
|
||||
if(CLANG_TIDY)
|
||||
find_program(CLANG_TIDY_BINARY NAMES clang-tidy)
|
||||
|
@ -58,14 +59,7 @@ endif()
|
|||
#---------------------------------------------------------------------------------------------------
|
||||
# OpenGL setup.
|
||||
|
||||
# Check if we're running on a Raspberry Pi.
|
||||
if(EXISTS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/bcm_host.h")
|
||||
message("-- Building on a Raspberry Pi (bcm_host.h found)")
|
||||
# Setting BCMHOST seems to break OpenGL ES on the RPi 4 so set RPI instead.
|
||||
#set(BCMHOST found)
|
||||
set(RPI ON)
|
||||
set(GLSYSTEM "Embedded OpenGL" CACHE STRING "The OpenGL system to be used")
|
||||
elseif(GLES OR RPI)
|
||||
if(GLES)
|
||||
set(GLSYSTEM "Embedded OpenGL" CACHE STRING "The OpenGL system to be used")
|
||||
else()
|
||||
set(GLSYSTEM "Desktop OpenGL" CACHE STRING "The OpenGL system to be used")
|
||||
|
@ -73,6 +67,32 @@ endif()
|
|||
|
||||
set_property(CACHE GLSYSTEM PROPERTY STRINGS "Desktop OpenGL" "Embedded OpenGL")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
# Raspberry Pi setup.
|
||||
|
||||
# If manually set to RPI (used for testing purposes).
|
||||
if(RPI)
|
||||
set(VIDEO_HW_DECODING OFF)
|
||||
endif()
|
||||
|
||||
# Raspberry Pi OS 32-bit (armv7l)
|
||||
if(EXISTS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include/bcm_host.h")
|
||||
set(RPI ON)
|
||||
set(RPI_32 ON)
|
||||
set(VIDEO_HW_DECODING OFF)
|
||||
set(BCMHOST found)
|
||||
message("-- Building on a Raspberry Pi (32-bit OS)")
|
||||
endif()
|
||||
|
||||
# Raspberry Pi OS 64-bit (aarch64)
|
||||
if(EXISTS "/usr/include/bcm_host.h")
|
||||
set(RPI ON)
|
||||
set(RPI_64 ON)
|
||||
set(VIDEO_HW_DECODING OFF)
|
||||
set(BCMHOST found)
|
||||
message("-- Building on a Raspberry Pi (64-bit OS)")
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
# Package dependencies.
|
||||
|
||||
|
@ -196,18 +216,22 @@ else()
|
|||
add_definitions(-DUSE_OPENGLES_10)
|
||||
endif()
|
||||
|
||||
if(RPI)
|
||||
add_definitions(-D_RPI_)
|
||||
endif()
|
||||
|
||||
if(VLC_PLAYER)
|
||||
add_definitions(-DBUILD_VLC_PLAYER)
|
||||
endif()
|
||||
|
||||
if(DEFINED BCMHOST OR RPI)
|
||||
add_definitions(-D_RPI_)
|
||||
endif()
|
||||
|
||||
if(DEFINED libCEC_FOUND)
|
||||
add_definitions(-DHAVE_LIBCEC)
|
||||
endif()
|
||||
|
||||
if(VIDEO_HW_DECODING)
|
||||
add_definitions(-DVIDEO_HW_DECODING)
|
||||
endif()
|
||||
|
||||
# GLM library options.
|
||||
add_definitions(-DGLM_FORCE_CXX17)
|
||||
add_definitions(-DGLM_FORCE_XYZW_ONLY)
|
||||
|
@ -279,7 +303,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
|||
list(APPEND COMMON_INCLUDE_DIRS ${ALSA_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(DEFINED BCMHOST OR RPI)
|
||||
if(RPI_32)
|
||||
list(APPEND COMMON_INCLUDE_DIRS "${CMAKE_FIND_ROOT_PATH}/opt/vc/include"
|
||||
"${CMAKE_FIND_ROOT_PATH}/opt/vc/include/interface/vcos"
|
||||
"${CMAKE_FIND_ROOT_PATH}/opt/vc/include/interface/vmcs_host/linux"
|
||||
|
@ -358,9 +382,6 @@ endif()
|
|||
|
||||
# Add libCEC libraries.
|
||||
if(DEFINED libCEC_FOUND)
|
||||
if(DEFINED BCMHOST OR RPI)
|
||||
list(APPEND COMMON_LIBRARIES bcm_host vchiq_arm)
|
||||
endif()
|
||||
list(APPEND COMMON_LIBRARIES dl ${libCEC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
@ -369,14 +390,22 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
|||
list(APPEND COMMON_LIBRARIES ${ALSA_LIBRARY})
|
||||
endif()
|
||||
|
||||
# Raspberry Pi.
|
||||
if(DEFINED BCMHOST)
|
||||
link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib")
|
||||
list(APPEND COMMON_LIBRARIES bcm_host brcmEGL ${OPENGLES_LIBRARIES})
|
||||
elseif(RPI)
|
||||
link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib")
|
||||
list(APPEND COMMON_LIBRARIES bcm_host vchiq_arm)
|
||||
if(RPI_32)
|
||||
link_directories("${CMAKE_FIND_ROOT_PATH}/opt/vc/lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Note: Building with GLES support on the Raspberry Pi currently seems to be broken.
|
||||
if(GLES AND RPI_32)
|
||||
list(APPEND COMMON_LIBRARIES brcmEGL ${OPENGLES_LIBRARIES})
|
||||
elseif(GLES AND RPI_64)
|
||||
list(APPEND COMMON_LIBRARIES ${OPENGLES_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# OpenGL.
|
||||
if(GLSYSTEM MATCHES "Desktop OpenGL")
|
||||
list(APPEND COMMON_LIBRARIES ${OPENGL_LIBRARIES})
|
||||
else()
|
||||
|
|
|
@ -133,9 +133,6 @@ GuiGameScraper::GuiGameScraper(Window* window,
|
|||
static_cast<float>(Renderer::getScreenHeight()) * 0.04f +
|
||||
mButtonGrid->getSize().y + Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f;
|
||||
|
||||
// TODO: Temporary hack, see below.
|
||||
height -= 7.0f * Renderer::getScreenHeightModifier();
|
||||
|
||||
setSize(width, height);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
|
||||
(Renderer::getScreenHeight() - mSize.y) / 2.0f);
|
||||
|
@ -154,17 +151,11 @@ void GuiGameScraper::onSizeChanged()
|
|||
mSize.y / 2.0f);
|
||||
mGrid.setRowHeightPerc(2, mSystemName->getFont()->getLetterHeight() / mSize.y, false);
|
||||
mGrid.setRowHeightPerc(3, 0.04f, false);
|
||||
mGrid.setRowHeightPerc(4, ((Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f)) / mSize.y, false);
|
||||
|
||||
// TODO: Replace this temporary hack with a proper solution. There is some kind of rounding
|
||||
// issue somewhere that causes a small alignment error. This code partly compensates for this
|
||||
// at higher resolutions than 1920x1080.
|
||||
if (Renderer::getScreenHeightModifier() > 1.0f)
|
||||
mSize.y -= 3.0f * Renderer::getScreenHeightModifier();
|
||||
mGrid.setRowHeightPerc(4, (Font::get(FONT_SIZE_MEDIUM)->getHeight() * 8.0f) / mSize.y, false);
|
||||
|
||||
mGrid.setColWidthPerc(1, 0.04f);
|
||||
|
||||
mGrid.setSize(mSize);
|
||||
mGrid.setSize(glm::round(mSize));
|
||||
mBox.fitTo(mSize, glm::vec3{}, glm::vec2{-32.0f, -32.0f});
|
||||
|
||||
// Add some extra margins to the game name.
|
||||
|
|
|
@ -1010,7 +1010,7 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_RPI_)
|
||||
#if defined(VIDEO_HW_DECODING)
|
||||
// Whether to enable hardware decoding for the FFmpeg video player.
|
||||
auto video_hardware_decoding = std::make_shared<SwitchComponent>(mWindow);
|
||||
video_hardware_decoding->setState(Settings::getInstance()->getBool("VideoHardwareDecoding"));
|
||||
|
|
|
@ -32,6 +32,11 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
|||
// just in case the scraper from settings has vanished.
|
||||
for (auto it = scrapers.cbegin(); it != scrapers.cend(); it++)
|
||||
mScraper->add(*it, *it, *it == Settings::getInstance()->getString("Scraper"));
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
// configuration file. Simply set the scraper to "screenscraper" in this case.
|
||||
if (mScraper->getSelectedObjects().size() == 0)
|
||||
mScraper->selectEntry(0);
|
||||
|
||||
mMenu.addWithLabel("SCRAPE FROM", mScraper);
|
||||
|
||||
// Search filters, getSearches() will generate a queue of games to scrape
|
||||
|
|
|
@ -32,7 +32,14 @@ const std::map<std::string, generate_scraper_requests_func> scraper_request_func
|
|||
|
||||
std::unique_ptr<ScraperSearchHandle> startScraperSearch(const ScraperSearchParams& params)
|
||||
{
|
||||
const std::string& name = Settings::getInstance()->getString("Scraper");
|
||||
std::string name = Settings::getInstance()->getString("Scraper");
|
||||
// Handle a potentially invalid entry in the configuration file.
|
||||
if (name != "screenscraper" && name != "thegamesdb") {
|
||||
name = "screenscraper";
|
||||
Settings::getInstance()->setString("Scraper", name);
|
||||
Settings::getInstance()->saveFile();
|
||||
}
|
||||
|
||||
std::unique_ptr<ScraperSearchHandle> handle(new ScraperSearchHandle());
|
||||
|
||||
// Check if the scraper in the settings still exists as a registered scraping source.
|
||||
|
|
|
@ -39,6 +39,12 @@ UIModeController::UIModeController()
|
|||
{
|
||||
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
|
||||
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
|
||||
// Handle a potentially invalid entry in the configuration file.
|
||||
if (mCurrentUIMode != "full" && mCurrentUIMode != "kid" && mCurrentUIMode != "kiosk") {
|
||||
mCurrentUIMode = "full";
|
||||
Settings::getInstance()->setString("UIMode", mCurrentUIMode);
|
||||
Settings::getInstance()->saveFile();
|
||||
}
|
||||
}
|
||||
|
||||
void UIModeController::monitorUIMode()
|
||||
|
|
|
@ -98,7 +98,7 @@ void Settings::setDefaults()
|
|||
|
||||
// Scraper.
|
||||
mStringMap["Scraper"] = {"screenscraper", "screenscraper"};
|
||||
mBoolMap["ScraperUseAccountScreenScraper"] = {false, false};
|
||||
mBoolMap["ScraperUseAccountScreenScraper"] = {true, true};
|
||||
mStringMap["ScraperUsernameScreenScraper"] = {"", ""};
|
||||
mStringMap["ScraperPasswordScreenScraper"] = {"", ""};
|
||||
|
||||
|
@ -154,7 +154,11 @@ void Settings::setDefaults()
|
|||
// UI settings -> media viewer settings.
|
||||
mBoolMap["MediaViewerKeepVideoRunning"] = {true, true};
|
||||
mBoolMap["MediaViewerStretchVideos"] = {false, false};
|
||||
#if defined(_RPI_)
|
||||
mBoolMap["MediaViewerVideoScanlines"] = {false, false};
|
||||
#else
|
||||
mBoolMap["MediaViewerVideoScanlines"] = {true, true};
|
||||
#endif
|
||||
mBoolMap["MediaViewerVideoBlur"] = {false, false};
|
||||
mBoolMap["MediaViewerScreenshotScanlines"] = {true, true};
|
||||
|
||||
|
@ -177,7 +181,11 @@ void Settings::setDefaults()
|
|||
mIntMap["ScreensaverSwapVideoTimeout"] = {0, 0};
|
||||
mBoolMap["ScreensaverStretchVideos"] = {false, false};
|
||||
mBoolMap["ScreensaverVideoGameInfo"] = {true, true};
|
||||
#if defined(_RPI_)
|
||||
mBoolMap["ScreensaverVideoScanlines"] = {false, false};
|
||||
#else
|
||||
mBoolMap["ScreensaverVideoScanlines"] = {true, true};
|
||||
#endif
|
||||
mBoolMap["ScreensaverVideoBlur"] = {false, false};
|
||||
|
||||
mBoolMap["MenuBlurBackground"] = {true, true};
|
||||
|
@ -199,8 +207,8 @@ void Settings::setDefaults()
|
|||
mBoolMap["EnableMenuKidMode"] = {false, false};
|
||||
|
||||
// Sound settings.
|
||||
mIntMap["SoundVolumeNavigation"] = {80, 80};
|
||||
mIntMap["SoundVolumeVideos"] = {100, 100};
|
||||
mIntMap["SoundVolumeNavigation"] = {70, 70};
|
||||
mIntMap["SoundVolumeVideos"] = {80, 80};
|
||||
mBoolMap["GamelistVideoAudio"] = {true, true};
|
||||
mBoolMap["MediaViewerVideoAudio"] = {true, true};
|
||||
mBoolMap["ScreensaverVideoAudio"] = {false, false};
|
||||
|
@ -221,7 +229,7 @@ void Settings::setDefaults()
|
|||
// Other settings.
|
||||
mStringMap["MediaDirectory"] = {"", ""};
|
||||
#if defined(_RPI_)
|
||||
mIntMap["MaxVRAM"] = {80, 80};
|
||||
mIntMap["MaxVRAM"] = {180, 180};
|
||||
#else
|
||||
mIntMap["MaxVRAM"] = {256, 256};
|
||||
#endif
|
||||
|
@ -230,12 +238,7 @@ void Settings::setDefaults()
|
|||
mStringMap["FullscreenMode"] = {"normal", "normal"};
|
||||
#endif
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
#if defined(_RPI_)
|
||||
// As the FFmpeg video player is not HW accelerated, use VLC as default on this weak device.
|
||||
mStringMap["VideoPlayer"] = {"vlc", "vlc"};
|
||||
#else
|
||||
mStringMap["VideoPlayer"] = {"ffmpeg", "ffmpeg"};
|
||||
#endif
|
||||
#endif
|
||||
mStringMap["ExitButtonCombo"] = {"F4", "F4"};
|
||||
mStringMap["SaveGamelistsMode"] = {"always", "always"};
|
||||
|
@ -246,7 +249,7 @@ void Settings::setDefaults()
|
|||
#if defined(_WIN64)
|
||||
mBoolMap["LaunchWorkaround"] = {true, true};
|
||||
#endif
|
||||
#if !defined(_RPI_)
|
||||
#if !defined(VIDEO_HW_DECODING)
|
||||
mBoolMap["VideoHardwareDecoding"] = {false, false};
|
||||
#endif
|
||||
mBoolMap["VideoUpscaleFrameRate"] = {false, false};
|
||||
|
@ -358,16 +361,9 @@ void Settings::saveFile()
|
|||
|
||||
void Settings::loadFile()
|
||||
{
|
||||
// Prior to ES-DE v1.1, the configuration file had the .cfg suffix instead of .xml
|
||||
const std::string legacyConfigFile =
|
||||
Utils::FileSystem::getHomePath() + "/.emulationstation/es_settings.cfg";
|
||||
|
||||
const std::string configFile =
|
||||
Utils::FileSystem::getHomePath() + "/.emulationstation/es_settings.xml";
|
||||
|
||||
if (Utils::FileSystem::exists(legacyConfigFile) && !Utils::FileSystem::exists(configFile))
|
||||
Utils::FileSystem::copyFile(legacyConfigFile, configFile, false);
|
||||
|
||||
if (!Utils::FileSystem::exists(configFile))
|
||||
return;
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@ bool Window::init()
|
|||
mBackgroundOverlay->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
||||
static_cast<float>(Renderer::getScreenHeight()));
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
mPostprocessedBackground = TextureResource::get("");
|
||||
#endif
|
||||
|
||||
mListScrollFont = Font::get(FONT_SIZE_LARGE);
|
||||
|
||||
// Update our help because font sizes probably changed.
|
||||
|
@ -143,6 +147,10 @@ void Window::deinit()
|
|||
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
|
||||
(*it)->onHide();
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
mPostprocessedBackground.reset();
|
||||
#endif
|
||||
|
||||
InputManager::getInstance()->deinit();
|
||||
ResourceManager::getInstance()->unloadAll();
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
|
@ -429,9 +437,6 @@ void Window::render()
|
|||
#if (CLOCK_BACKGROUND_CREATION)
|
||||
const auto backgroundStartTime = std::chrono::system_clock::now();
|
||||
#endif
|
||||
|
||||
std::shared_ptr<TextureResource> mPostprocessedBackground;
|
||||
mPostprocessedBackground = TextureResource::get("");
|
||||
unsigned char* processedTexture =
|
||||
new unsigned char[Renderer::getScreenWidth() * Renderer::getScreenHeight() * 4];
|
||||
|
||||
|
|
|
@ -167,6 +167,10 @@ private:
|
|||
|
||||
std::queue<std::pair<std::string, int>> mInfoPopupQueue;
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
std::shared_ptr<TextureResource> mPostprocessedBackground;
|
||||
#endif
|
||||
|
||||
std::string mListScrollText;
|
||||
std::shared_ptr<Font> mListScrollFont;
|
||||
unsigned char mListScrollOpacity;
|
||||
|
|
|
@ -289,7 +289,7 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
|
||||
dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y;
|
||||
|
||||
const int clipRectPosX{static_cast<int>(std::round(trans[3].x))};
|
||||
const int clipRectPosX{static_cast<int>(std::ceil(trans[3].x))};
|
||||
const int clipRectPosY{static_cast<int>(std::round(trans[3].y))};
|
||||
const int clipRectSizeX{static_cast<int>(std::round(dim.x))};
|
||||
const int clipRectSizeY{static_cast<int>(std::round(dim.y))};
|
||||
|
@ -383,12 +383,12 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
||||
|
||||
if (opacity == 1) {
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, false, opacity, trans,
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, false, opacity, trans,
|
||||
Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO);
|
||||
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0x777777FF,
|
||||
0x777777FF, false, opacity, trans, Renderer::Blend::ONE,
|
||||
Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight,
|
||||
0x777777FF, 0x777777FF, false, opacity, trans, Renderer::Blend::ONE,
|
||||
Renderer::Blend::ONE);
|
||||
}
|
||||
|
||||
|
@ -403,13 +403,13 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
// Draw separators.
|
||||
float y = 0;
|
||||
for (unsigned int i = 0; i < mEntries.size(); i++) {
|
||||
Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF,
|
||||
0xC6C7C6FF, false, opacity, trans);
|
||||
Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(),
|
||||
0xC6C7C6FF, 0xC6C7C6FF, false, opacity, trans);
|
||||
y += getRowHeight(mEntries.at(i).data);
|
||||
}
|
||||
|
||||
Renderer::drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF,
|
||||
0xC6C7C6FF, false, opacity, trans);
|
||||
Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(),
|
||||
0xC6C7C6FF, 0xC6C7C6FF, false, opacity, trans);
|
||||
Renderer::popClipRect();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "resources/TextureResource.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
enum AVHWDeviceType VideoFFmpegComponent::sDeviceType = AV_HWDEVICE_TYPE_NONE;
|
||||
enum AVPixelFormat VideoFFmpegComponent::sPixelFormat = AV_PIX_FMT_NONE;
|
||||
|
@ -165,17 +166,22 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
|||
mPictureMutex.lock();
|
||||
|
||||
if (!mOutputPicture.hasBeenRendered) {
|
||||
// Copy the contents of mOutputPicture to a temporary vector in order to call
|
||||
// Move the contents of mOutputPicture to a temporary vector in order to call
|
||||
// initFromPixels() only after the mutex unlock. This significantly reduces the
|
||||
// lock waits in outputFrames().
|
||||
size_t pictureSize = mOutputPicture.pictureRGBA.size();
|
||||
std::vector<uint8_t> tempPictureRGBA(pictureSize);
|
||||
std::vector<uint8_t> tempPictureRGBA;
|
||||
int pictureWidth = 0;
|
||||
int pictureHeight = 0;
|
||||
|
||||
if (pictureSize > 0) {
|
||||
tempPictureRGBA.insert(tempPictureRGBA.begin(), mOutputPicture.pictureRGBA.begin(),
|
||||
mOutputPicture.pictureRGBA.end());
|
||||
tempPictureRGBA.insert(tempPictureRGBA.begin(),
|
||||
std::make_move_iterator(mOutputPicture.pictureRGBA.begin()),
|
||||
std::make_move_iterator(mOutputPicture.pictureRGBA.end()));
|
||||
|
||||
mOutputPicture.pictureRGBA.erase(mOutputPicture.pictureRGBA.begin(),
|
||||
mOutputPicture.pictureRGBA.end());
|
||||
|
||||
pictureWidth = mOutputPicture.width;
|
||||
pictureHeight = mOutputPicture.height;
|
||||
|
||||
|
@ -528,90 +534,126 @@ void VideoFFmpegComponent::readFrames()
|
|||
if (mVideoFrameQueue.size() > 300 || mAudioFrameQueue.size() > 600)
|
||||
return;
|
||||
|
||||
int readLoops = 1;
|
||||
|
||||
// If we can't keep up the audio processing, then drop video frames as it's much worse
|
||||
// to have stuttering audio than a lower video framerate.
|
||||
if (mAudioStreamIndex >= 0 && mAudioFrameCount > mAudioTargetQueueSize / 2) {
|
||||
if (static_cast<int>(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 6)
|
||||
readLoops = 5;
|
||||
else if (static_cast<int>(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 4)
|
||||
readLoops = 3;
|
||||
else if (static_cast<int>(mAudioFrameQueue.size()) < mAudioTargetQueueSize / 2)
|
||||
readLoops = 2;
|
||||
}
|
||||
|
||||
if (mVideoCodecContext && mFormatContext) {
|
||||
if (static_cast<int>(mVideoFrameQueue.size()) < mVideoTargetQueueSize ||
|
||||
(mAudioStreamIndex >= 0 &&
|
||||
static_cast<int>(mAudioFrameQueue.size()) < mAudioTargetQueueSize)) {
|
||||
while ((readFrameReturn = av_read_frame(mFormatContext, mPacket)) >= 0) {
|
||||
if (mPacket->stream_index == mVideoStreamIndex) {
|
||||
if (!avcodec_send_packet(mVideoCodecContext, mPacket) &&
|
||||
!avcodec_receive_frame(mVideoCodecContext, mVideoFrame)) {
|
||||
for (int i = 0; i < readLoops; i++) {
|
||||
if (static_cast<int>(mVideoFrameQueue.size()) < mVideoTargetQueueSize ||
|
||||
(mAudioStreamIndex >= 0 &&
|
||||
static_cast<int>(mAudioFrameQueue.size()) < mAudioTargetQueueSize)) {
|
||||
while ((readFrameReturn = av_read_frame(mFormatContext, mPacket)) >= 0) {
|
||||
if (mPacket->stream_index == mVideoStreamIndex) {
|
||||
if (!avcodec_send_packet(mVideoCodecContext, mPacket) &&
|
||||
!avcodec_receive_frame(mVideoCodecContext, mVideoFrame)) {
|
||||
|
||||
int returnValue = 0;
|
||||
int returnValue = 0;
|
||||
mVideoFrameReadCount++;
|
||||
|
||||
if (mSWDecoder) {
|
||||
returnValue = av_buffersrc_add_frame_flags(
|
||||
mVBufferSrcContext, mVideoFrame, AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT);
|
||||
}
|
||||
else {
|
||||
AVFrame* destFrame = nullptr;
|
||||
destFrame = av_frame_alloc();
|
||||
|
||||
if (mVideoFrame->format == sPixelFormat) {
|
||||
if (av_hwframe_transfer_data(destFrame, mVideoFrame, 0) < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't transfer decoded video frame to "
|
||||
"system memory";
|
||||
av_frame_free(&destFrame);
|
||||
av_packet_unref(mPacket);
|
||||
break;
|
||||
if (mSWDecoder) {
|
||||
// Drop the frame if necessary.
|
||||
if (i == 0 || mAudioFrameCount == 0) {
|
||||
returnValue = av_buffersrc_add_frame_flags(
|
||||
mVBufferSrcContext, mVideoFrame,
|
||||
AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT);
|
||||
}
|
||||
else {
|
||||
destFrame->pts = mVideoFrame->pts;
|
||||
destFrame->pkt_dts = mVideoFrame->pkt_dts;
|
||||
destFrame->pict_type = mVideoFrame->pict_type;
|
||||
destFrame->chroma_location = mVideoFrame->chroma_location;
|
||||
destFrame->pkt_pos = mVideoFrame->pkt_pos;
|
||||
destFrame->pkt_duration = mVideoFrame->pkt_duration;
|
||||
destFrame->pkt_size = mVideoFrame->pkt_size;
|
||||
mVideoFrameDroppedCount++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't decode video frame";
|
||||
if (i == 0 || mAudioFrameCount == 0) {
|
||||
AVFrame* destFrame = nullptr;
|
||||
destFrame = av_frame_alloc();
|
||||
|
||||
if (mVideoFrame->format == sPixelFormat) {
|
||||
if (av_hwframe_transfer_data(destFrame, mVideoFrame, 0) <
|
||||
0) {
|
||||
LOG(LogError)
|
||||
<< "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't transfer decoded video frame to "
|
||||
"system memory";
|
||||
av_frame_free(&destFrame);
|
||||
av_packet_unref(mPacket);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
destFrame->pts = mVideoFrame->pts;
|
||||
destFrame->pkt_dts = mVideoFrame->pkt_dts;
|
||||
destFrame->pict_type = mVideoFrame->pict_type;
|
||||
destFrame->chroma_location =
|
||||
mVideoFrame->chroma_location;
|
||||
destFrame->pkt_pos = mVideoFrame->pkt_pos;
|
||||
destFrame->pkt_duration = mVideoFrame->pkt_duration;
|
||||
destFrame->pkt_size = mVideoFrame->pkt_size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't decode video frame";
|
||||
}
|
||||
|
||||
returnValue = av_buffersrc_add_frame_flags(
|
||||
mVBufferSrcContext, destFrame,
|
||||
AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT);
|
||||
av_frame_free(&destFrame);
|
||||
}
|
||||
else {
|
||||
mVideoFrameDroppedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
returnValue = av_buffersrc_add_frame_flags(
|
||||
mVBufferSrcContext, destFrame, AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT);
|
||||
av_frame_free(&destFrame);
|
||||
}
|
||||
if (returnValue < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't add video frame to buffer source";
|
||||
}
|
||||
|
||||
if (returnValue < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't add video frame to buffer source";
|
||||
av_packet_unref(mPacket);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
av_packet_unref(mPacket);
|
||||
}
|
||||
}
|
||||
else if (mPacket->stream_index == mAudioStreamIndex) {
|
||||
if (!avcodec_send_packet(mAudioCodecContext, mPacket) &&
|
||||
!avcodec_receive_frame(mAudioCodecContext, mAudioFrame)) {
|
||||
|
||||
av_packet_unref(mPacket);
|
||||
break;
|
||||
// We have an audio frame that needs conversion and resampling.
|
||||
int returnValue = av_buffersrc_add_frame_flags(
|
||||
mABufferSrcContext, mAudioFrame, AV_BUFFERSRC_FLAG_KEEP_REF);
|
||||
|
||||
if (returnValue < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't add audio frame to buffer source";
|
||||
}
|
||||
|
||||
av_packet_unref(mPacket);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
av_packet_unref(mPacket);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ignore any stream that is not video or audio.
|
||||
av_packet_unref(mPacket);
|
||||
}
|
||||
}
|
||||
else if (mPacket->stream_index == mAudioStreamIndex) {
|
||||
if (!avcodec_send_packet(mAudioCodecContext, mPacket) &&
|
||||
!avcodec_receive_frame(mAudioCodecContext, mAudioFrame)) {
|
||||
|
||||
// We have an audio frame that needs conversion and resampling.
|
||||
int returnValue = av_buffersrc_add_frame_flags(
|
||||
mABufferSrcContext, mAudioFrame, AV_BUFFERSRC_FLAG_KEEP_REF);
|
||||
|
||||
if (returnValue < 0) {
|
||||
LOG(LogError) << "VideoFFmpegComponent::readFrames(): "
|
||||
"Couldn't add audio frame to buffer source";
|
||||
}
|
||||
|
||||
av_packet_unref(mPacket);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
av_packet_unref(mPacket);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ignore any stream that is not video or audio.
|
||||
av_packet_unref(mPacket);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The target queue sizes have been reached.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -649,10 +691,11 @@ void VideoFFmpegComponent::getProcessedFrames()
|
|||
|
||||
int bufferSize = mVideoFrameResampled->width * mVideoFrameResampled->height * 4;
|
||||
|
||||
currFrame.frameRGBA.insert(currFrame.frameRGBA.begin(), &mVideoFrameResampled->data[0][0],
|
||||
&mVideoFrameResampled->data[0][bufferSize]);
|
||||
currFrame.frameRGBA.insert(
|
||||
currFrame.frameRGBA.begin(), std::make_move_iterator(&mVideoFrameResampled->data[0][0]),
|
||||
std::make_move_iterator(&mVideoFrameResampled->data[0][bufferSize]));
|
||||
|
||||
mVideoFrameQueue.push(currFrame);
|
||||
mVideoFrameQueue.push(std::move(currFrame));
|
||||
av_frame_unref(mVideoFrameResampled);
|
||||
}
|
||||
|
||||
|
@ -680,7 +723,7 @@ void VideoFFmpegComponent::getProcessedFrames()
|
|||
&mAudioFrameResampled->data[0][0],
|
||||
&mAudioFrameResampled->data[0][bufferSize]);
|
||||
|
||||
mAudioFrameQueue.push(currFrame);
|
||||
mAudioFrameQueue.push(std::move(currFrame));
|
||||
av_frame_unref(mAudioFrameResampled);
|
||||
}
|
||||
}
|
||||
|
@ -751,6 +794,14 @@ void VideoFFmpegComponent::outputFrames()
|
|||
LOG(LogDebug) << "Total video frames processed / video frame queue size: "
|
||||
<< mVideoFrameCount << " / "
|
||||
<< std::to_string(mVideoFrameQueue.size());
|
||||
if (mVideoFrameDroppedCount > 0) {
|
||||
LOG(LogDebug) << "Video frames dropped: " << mVideoFrameDroppedCount << " of "
|
||||
<< mVideoFrameReadCount << " (" << std::setprecision(2)
|
||||
<< (static_cast<float>(mVideoFrameDroppedCount) /
|
||||
static_cast<float>(mVideoFrameReadCount)) *
|
||||
100.0f
|
||||
<< "%)";
|
||||
}
|
||||
}
|
||||
|
||||
mPictureMutex.lock();
|
||||
|
@ -1136,6 +1187,8 @@ void VideoFFmpegComponent::startVideo()
|
|||
mEndOfVideo = false;
|
||||
mVideoFrameCount = 0;
|
||||
mAudioFrameCount = 0;
|
||||
mVideoFrameReadCount = 0;
|
||||
mVideoFrameDroppedCount = 0;
|
||||
mOutputPicture = {};
|
||||
|
||||
// Get an empty texture for rendering the video.
|
||||
|
@ -1174,7 +1227,7 @@ void VideoFFmpegComponent::startVideo()
|
|||
|
||||
// Video stream setup.
|
||||
|
||||
#if defined(_RPI_)
|
||||
#if !defined(VIDEO_HW_DECODING)
|
||||
bool hwDecoding = false;
|
||||
#else
|
||||
bool hwDecoding = Settings::getInstance()->getBool("VideoHardwareDecoding");
|
||||
|
|
|
@ -158,6 +158,8 @@ private:
|
|||
|
||||
int mAudioFrameCount;
|
||||
int mVideoFrameCount;
|
||||
int mVideoFrameReadCount;
|
||||
int mVideoFrameDroppedCount;
|
||||
|
||||
double mAccumulatedTime;
|
||||
bool mStartTimeAccumulation;
|
||||
|
|
|
@ -105,8 +105,9 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
|
|||
|
||||
nsvgDeleteRasterizer(rast);
|
||||
|
||||
mDataRGBA.insert(mDataRGBA.begin(), tempVector.data(),
|
||||
tempVector.data() + (mWidth * mHeight * 4));
|
||||
mDataRGBA.insert(mDataRGBA.begin(), std::make_move_iterator(tempVector.data()),
|
||||
std::make_move_iterator(tempVector.data() + (mWidth * mHeight * 4)));
|
||||
tempVector.erase(tempVector.begin(), tempVector.end());
|
||||
|
||||
ImageIO::flipPixelsVert(mDataRGBA.data(), mWidth, mHeight);
|
||||
mPendingRasterization = false;
|
||||
|
@ -160,7 +161,8 @@ bool TextureData::initFromRGBA(const unsigned char* dataRGBA, size_t width, size
|
|||
return true;
|
||||
|
||||
mDataRGBA.reserve(width * height * 4);
|
||||
mDataRGBA.insert(mDataRGBA.begin(), dataRGBA, dataRGBA + (width * height * 4));
|
||||
mDataRGBA.insert(mDataRGBA.begin(), std::make_move_iterator(dataRGBA),
|
||||
std::make_move_iterator(dataRGBA + (width * height * 4)));
|
||||
|
||||
mWidth = static_cast<int>(width);
|
||||
mHeight = static_cast<int>(height);
|
||||
|
|
Loading…
Reference in a new issue