From 32177e058355f9ad504ffb2136f1d9a79c9cbd6e Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 26 Nov 2025 21:31:21 +0100 Subject: [PATCH] FFmpeg parser: better fallback for streams that do not expose bitrate --- src/libs/audio/impl/ffmpeg/AudioFile.cpp | 8 +++-- src/libs/audio/impl/ffmpeg/AudioFile.hpp | 2 +- src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp | 37 ++++++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/libs/audio/impl/ffmpeg/AudioFile.cpp b/src/libs/audio/impl/ffmpeg/AudioFile.cpp index 7f679b99..9e5eed5c 100644 --- a/src/libs/audio/impl/ffmpeg/AudioFile.cpp +++ b/src/libs/audio/impl/ffmpeg/AudioFile.cpp @@ -32,6 +32,7 @@ extern "C" } #include "core/ILogger.hpp" +#include "core/ITraceLogger.hpp" #include "core/String.hpp" #include "audio/AudioTypes.hpp" @@ -189,7 +190,7 @@ namespace lms::audio::ffmpeg std::array buffer{ 0 }; std::vsnprintf(buffer.data(), buffer.size(), fmt, vl); - LMS_LOG(AUDIO, DEBUG, "ffmpeg [" << avLogLevelToStr(level) << "] " << buffer.data()); + LMS_LOG(AUDIO, DEBUG, "FFmpeg [" << avLogLevelToStr(level) << "] " << buffer.data()); } class AvInitializer @@ -205,6 +206,8 @@ namespace lms::audio::ffmpeg AudioFile::AudioFile(const std::filesystem::path& p) : _p{ p } { + LMS_SCOPED_TRACE_DETAILED("MetaData", "FFmpegParseFile"); + static AvInitializer init; int error{ avformat_open_input(&_context, _p.c_str(), nullptr, nullptr) }; @@ -240,7 +243,8 @@ namespace lms::audio::ffmpeg info.container = avdemuxerToContainerType(_context->iformat->name); info.containerName = _context->iformat->name; - info.bitrate = _context->bit_rate; + if (_context->bit_rate > 0) + info.bitrate = _context->bit_rate; info.duration = std::chrono::milliseconds{ _context->duration == AV_NOPTS_VALUE ? 0 : _context->duration / AV_TIME_BASE * 1'000 }; return info; diff --git a/src/libs/audio/impl/ffmpeg/AudioFile.hpp b/src/libs/audio/impl/ffmpeg/AudioFile.hpp index 64c4303d..fde8a031 100644 --- a/src/libs/audio/impl/ffmpeg/AudioFile.hpp +++ b/src/libs/audio/impl/ffmpeg/AudioFile.hpp @@ -47,7 +47,7 @@ namespace lms::audio::ffmpeg std::optional container; std::string containerName; - std::size_t bitrate{}; + std::optional bitrate; std::chrono::milliseconds duration{}; }; diff --git a/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp b/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp index f1ebbcc6..62fe54e4 100644 --- a/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp +++ b/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp @@ -19,6 +19,9 @@ #include "AudioFileInfo.hpp" +#include +#include + #include "core/ILogger.hpp" #include "audio/AudioTypes.hpp" @@ -44,6 +47,12 @@ namespace lms::audio::ffmpeg return audioProperties; } + if (containerInfo.duration.count() == 0) + { + LMS_LOG(AUDIO, DEBUG, "Cannot determine duration in " << audioFile.getPath()); + return audioProperties; + } + if (!containerInfo.container) { LMS_LOG(AUDIO, DEBUG, "Unhandled container '" << containerInfo.containerName << "' in " << audioFile.getPath()); @@ -56,12 +65,6 @@ namespace lms::audio::ffmpeg return audioProperties; } - if (!bestStreamInfo->bitrate || *bestStreamInfo->bitrate == 0) - { - LMS_LOG(AUDIO, DEBUG, "Cannot determine bitrate in " << audioFile.getPath()); - return audioProperties; - } - if (!bestStreamInfo->channelCount || *bestStreamInfo->channelCount == 0) { LMS_LOG(AUDIO, DEBUG, "Cannot determine channel count in " << audioFile.getPath()); @@ -79,7 +82,27 @@ namespace lms::audio::ffmpeg audioProperties->container = *containerInfo.container; audioProperties->duration = containerInfo.duration; audioProperties->codec = *bestStreamInfo->codec; - audioProperties->bitrate = *bestStreamInfo->bitrate; + + if (bestStreamInfo->bitrate) + audioProperties->bitrate = *bestStreamInfo->bitrate; + else if (containerInfo.bitrate) + audioProperties->bitrate = *containerInfo.bitrate; + else // Fallback on a bitrate based on duration/size + { + std::error_code ec; + const auto fileSize{ std::filesystem::file_size(audioFile.getPath(), ec) }; + if (ec) + { + LMS_LOG(AUDIO, DEBUG, "Cannot determine file size for " << audioFile.getPath() << ": " << ec.message()); + audioProperties.reset(); + return audioProperties; + } + + audioProperties->bitrate = static_cast(std::chrono::duration_cast>(containerInfo.duration).count() / fileSize); + LMS_LOG(AUDIO, DEBUG, "Estimated bitrate from duration/size: " << audioProperties->bitrate << " bps in " << audioFile.getPath()); + } + assert(audioProperties->bitrate > 0); + audioProperties->channelCount = *bestStreamInfo->channelCount; audioProperties->sampleRate = *bestStreamInfo->sampleRate; audioProperties->bitsPerSample = bestStreamInfo->bitsPerSample;