From 6210b2220575b5b379e15a41186ed8381f398c23 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 15 Jan 2026 15:51:12 +0100 Subject: [PATCH 1/3] Add a quiet option for some filesystem methods that only perform tests while keeping old behavior s default for compatibility --- .../Helper/src/sofa/helper/system/FileSystem.cpp | 16 +++++++++------- .../Helper/src/sofa/helper/system/FileSystem.h | 12 ++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp index e3c963d724a..8d506694cff 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.cpp @@ -209,7 +209,7 @@ bool FileSystem::removeDirectory(const std::string& path) } -bool FileSystem::exists(const std::string& path) +bool FileSystem::exists(const std::string& path, bool quiet) { #if defined(WIN32) ::SetLastError(0); @@ -231,14 +231,15 @@ bool FileSystem::exists(const std::string& path) if (errno == ENOENT) // No such file or directory return false; else { - msg_error("FileSystem::exists()") << path << ": " << strerror(errno); + if (!quiet) + msg_error("FileSystem::exists()") << path << ": " << strerror(errno); return false; } #endif } -bool FileSystem::isDirectory(const std::string& path) +bool FileSystem::isDirectory(const std::string& path, bool quiet) { #if defined(WIN32) const DWORD fileAttrib = GetFileAttributes(sofa::helper::widenString(path).c_str()); @@ -251,7 +252,8 @@ bool FileSystem::isDirectory(const std::string& path) #else struct stat st_buf; if (stat(path.c_str(), &st_buf) != 0) { - msg_error("FileSystem::isDirectory()") << path << ": " << strerror(errno); + if (!quiet) + msg_error("FileSystem::isDirectory()") << path << ": " << strerror(errno); return false; } else @@ -331,11 +333,11 @@ bool FileSystem::isAbsolute(const std::string& path) || path[0] == '/'); } -bool FileSystem::isFile(const std::string &path) +bool FileSystem::isFile(const std::string &path, bool quiet) { return - FileSystem::exists(path) && - !FileSystem::isDirectory(path) + FileSystem::exists(path, quiet) && + !FileSystem::isDirectory(path, quiet) ; } diff --git a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h index ace9bfd9a13..65897c9df4e 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h +++ b/Sofa/framework/Helper/src/sofa/helper/system/FileSystem.h @@ -119,19 +119,19 @@ static void ensureFolderExists(const std::string& pathToFolder); /// @note The function assumes that a path to a file is given. static void ensureFolderForFileExists(const std::string& pathToFile); -/// @brief Return true if and only if the given file exists. -static bool exists(const std::string& path); +/// @brief Return true if and only if the given file exists. The call might display errors if quiet=false. +static bool exists(const std::string& path, bool quiet = false ); -/// @brief Return true if and only if the given file path corresponds to a directory. +/// @brief Return true if and only if the given file path corresponds to a directory. The call might display errors if quiet=false. /// /// @warning The path must exist. -static bool isDirectory(const std::string& path); +static bool isDirectory(const std::string& path, bool quiet = false); /// @brief Return true if and only if the given file path is absolute. static bool isAbsolute(const std::string& path); -/// @brief Return true if and only if the given file path is an existing file. -static bool isFile(const std::string& path); +/// @brief Return true if and only if the given file path is an existing file. The call might display errors if quiet=false. +static bool isFile(const std::string& path, bool quiet = false ); /// @brief Replace backslashes with slashes. static std::string convertBackSlashesToSlashes(const std::string& path); From 750f1a14fd6a2bb1a2e0cc843b90590b19378ce5 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Tue, 13 Jan 2026 18:22:42 +0100 Subject: [PATCH 2/3] Modify the FFMPeg recorder to be able to use it in SofaGLFW --- Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp | 25 ++++++++++++--------- Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.h | 5 +++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp index 26d07054bf1..a33602a6f51 100644 --- a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp +++ b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp @@ -138,31 +138,38 @@ void VideoRecorderFFMPEG::addFrame() { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - + if ((viewport[2] != m_viewportWidth) || (viewport[3] != m_viewportHeight)) { std::cout << "WARNING viewport changed during video capture from " << m_viewportWidth << "x" << m_viewportHeight << " to " << viewport[2] << "x" << viewport[3] << std::endl; } + glReadPixels(viewport[0], viewport[1], m_viewportWidth, m_viewportHeight, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_viewportBuffer); + + addFrame(m_viewportBuffer, m_viewportWidth, m_viewportHeight); +} + - glReadPixels(0, 0, m_viewportWidth, m_viewportHeight, GL_RGBA, GL_UNSIGNED_BYTE, (void*)m_viewportBuffer); - // set ffmpeg buffer: initialize to 0 (black) +void VideoRecorderFFMPEG::addFrame(unsigned char* rgbData, int fbWidth, int fbHeight) +{ + + // set ffmpeg buffer: initialize to 0 (black) memset(m_ffmpegBuffer, 0, m_ffmpegBufferSize); - if (m_viewportWidth == m_ffmpegWidth) + if (fbWidth == m_ffmpegWidth) { - memcpy(m_ffmpegBuffer, m_viewportBuffer, m_viewportBufferSize); + memcpy(m_ffmpegBuffer, rgbData, fbHeight * fbWidth * m_pixelFormatSize); } else { - const unsigned char* viewportBufferIter = m_viewportBuffer; - const size_t viewportRowSizeInBytes = m_pixelFormatSize * m_viewportWidth; + const unsigned char* viewportBufferIter = rgbData; + const size_t viewportRowSizeInBytes = m_pixelFormatSize * fbWidth; unsigned char* ffmpegBufferIter = m_ffmpegBuffer; const size_t ffmpegRowSizeInBytes = m_pixelFormatSize * m_ffmpegWidth; - int row = m_viewportHeight; + int row = fbHeight; while ( row-- > 0 ) { memcpy( ffmpegBufferIter, viewportBufferIter, viewportRowSizeInBytes); @@ -174,8 +181,6 @@ void VideoRecorderFFMPEG::addFrame() fwrite(m_ffmpegBuffer, m_ffmpegBufferSize, 1, m_ffmpeg); - - return; } void VideoRecorderFFMPEG::finishVideo() diff --git a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.h b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.h index cae5c266795..afed4779094 100644 --- a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.h +++ b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.h @@ -62,9 +62,14 @@ class SOFA_GL_API VideoRecorderFFMPEG bool init(const std::string& ffmpeg_exec_filepath, const std::string& filename, int width, int height, unsigned int framerate, unsigned int bitrate, const std::string& codec=""); void addFrame(); + void addFrame(unsigned char* rgbData, int fbWidth, int fbHeight); void saveVideo(); void finishVideo(); + int getPixelFormatSize() + { + return m_pixelFormatSize; + }; void setPrefix(const std::string v) { m_prefix = v; } From 81af9022a646d76d9e0e8f81b437281cbe79260e Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 15 Jan 2026 15:58:59 +0100 Subject: [PATCH 3/3] Quietly check for file exists --- Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp index a33602a6f51..4ec9d904e7b 100644 --- a/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp +++ b/Sofa/GL/src/sofa/gl/VideoRecorderFFMPEG.cpp @@ -96,8 +96,9 @@ bool VideoRecorderFFMPEG::init(const std::string& ffmpeg_exec_filepath, const st extension = ".exe"; #endif m_ffmpegExecPath = helper::Utils::getExecutablePath() + "/ffmpeg" + extension; - if(!FileSystem::isFile(m_ffmpegExecPath)) + if(!FileSystem::isFile(m_ffmpegExecPath, true)) { + msg_warning("VideoRecorderFFMPEG")<< "ffmpeg hasn't been found automatically. Falling back to simply calling ffmpeg"<< extension <<" and hope that the OS finds it on its own. " ; // Fallback to a relative FFMPEG (may be in system or exposed in PATH) m_ffmpegExecPath = "ffmpeg" + extension; }