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:
Sophia Hadash 2021-11-08 12:13:33 +01:00
commit b3e42a4a17
13 changed files with 240 additions and 140 deletions

View file

@ -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()

View file

@ -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.

View file

@ -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"));

View file

@ -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

View file

@ -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.

View file

@ -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()

View file

@ -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;

View file

@ -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];

View file

@ -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;

View file

@ -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();
}

View file

@ -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");

View file

@ -158,6 +158,8 @@ private:
int mAudioFrameCount;
int mVideoFrameCount;
int mVideoFrameReadCount;
int mVideoFrameDroppedCount;
double mAccumulatedTime;
bool mStartTimeAccumulation;

View file

@ -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);