FFmpeg parser: better fallback for streams that do not expose bitrate

This commit is contained in:
emeric
2025-11-26 21:31:21 +01:00
parent 41f59c2054
commit 32177e0583
3 changed files with 37 additions and 10 deletions
+6 -2
View File
@@ -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<char, 256> 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;
+1 -1
View File
@@ -47,7 +47,7 @@ namespace lms::audio::ffmpeg
std::optional<ContainerType> container;
std::string containerName;
std::size_t bitrate{};
std::optional<std::size_t> bitrate;
std::chrono::milliseconds duration{};
};
+30 -7
View File
@@ -19,6 +19,9 @@
#include "AudioFileInfo.hpp"
#include <filesystem>
#include <system_error>
#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::size_t>(std::chrono::duration_cast<std::chrono::duration<double>>(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;