FFmpeg parser: better fallback for streams that do not expose bitrate
This commit is contained in:
@@ -32,6 +32,7 @@ extern "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "core/ILogger.hpp"
|
#include "core/ILogger.hpp"
|
||||||
|
#include "core/ITraceLogger.hpp"
|
||||||
#include "core/String.hpp"
|
#include "core/String.hpp"
|
||||||
|
|
||||||
#include "audio/AudioTypes.hpp"
|
#include "audio/AudioTypes.hpp"
|
||||||
@@ -189,7 +190,7 @@ namespace lms::audio::ffmpeg
|
|||||||
std::array<char, 256> buffer{ 0 };
|
std::array<char, 256> buffer{ 0 };
|
||||||
std::vsnprintf(buffer.data(), buffer.size(), fmt, vl);
|
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
|
class AvInitializer
|
||||||
@@ -205,6 +206,8 @@ namespace lms::audio::ffmpeg
|
|||||||
AudioFile::AudioFile(const std::filesystem::path& p)
|
AudioFile::AudioFile(const std::filesystem::path& p)
|
||||||
: _p{ p }
|
: _p{ p }
|
||||||
{
|
{
|
||||||
|
LMS_SCOPED_TRACE_DETAILED("MetaData", "FFmpegParseFile");
|
||||||
|
|
||||||
static AvInitializer init;
|
static AvInitializer init;
|
||||||
|
|
||||||
int error{ avformat_open_input(&_context, _p.c_str(), nullptr, nullptr) };
|
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.container = avdemuxerToContainerType(_context->iformat->name);
|
||||||
info.containerName = _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 };
|
info.duration = std::chrono::milliseconds{ _context->duration == AV_NOPTS_VALUE ? 0 : _context->duration / AV_TIME_BASE * 1'000 };
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace lms::audio::ffmpeg
|
|||||||
std::optional<ContainerType> container;
|
std::optional<ContainerType> container;
|
||||||
std::string containerName;
|
std::string containerName;
|
||||||
|
|
||||||
std::size_t bitrate{};
|
std::optional<std::size_t> bitrate;
|
||||||
std::chrono::milliseconds duration{};
|
std::chrono::milliseconds duration{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
#include "AudioFileInfo.hpp"
|
#include "AudioFileInfo.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include "core/ILogger.hpp"
|
#include "core/ILogger.hpp"
|
||||||
|
|
||||||
#include "audio/AudioTypes.hpp"
|
#include "audio/AudioTypes.hpp"
|
||||||
@@ -44,6 +47,12 @@ namespace lms::audio::ffmpeg
|
|||||||
return audioProperties;
|
return audioProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (containerInfo.duration.count() == 0)
|
||||||
|
{
|
||||||
|
LMS_LOG(AUDIO, DEBUG, "Cannot determine duration in " << audioFile.getPath());
|
||||||
|
return audioProperties;
|
||||||
|
}
|
||||||
|
|
||||||
if (!containerInfo.container)
|
if (!containerInfo.container)
|
||||||
{
|
{
|
||||||
LMS_LOG(AUDIO, DEBUG, "Unhandled container '" << containerInfo.containerName << "' in " << audioFile.getPath());
|
LMS_LOG(AUDIO, DEBUG, "Unhandled container '" << containerInfo.containerName << "' in " << audioFile.getPath());
|
||||||
@@ -56,12 +65,6 @@ namespace lms::audio::ffmpeg
|
|||||||
return audioProperties;
|
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)
|
if (!bestStreamInfo->channelCount || *bestStreamInfo->channelCount == 0)
|
||||||
{
|
{
|
||||||
LMS_LOG(AUDIO, DEBUG, "Cannot determine channel count in " << audioFile.getPath());
|
LMS_LOG(AUDIO, DEBUG, "Cannot determine channel count in " << audioFile.getPath());
|
||||||
@@ -79,7 +82,27 @@ namespace lms::audio::ffmpeg
|
|||||||
audioProperties->container = *containerInfo.container;
|
audioProperties->container = *containerInfo.container;
|
||||||
audioProperties->duration = containerInfo.duration;
|
audioProperties->duration = containerInfo.duration;
|
||||||
audioProperties->codec = *bestStreamInfo->codec;
|
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->channelCount = *bestStreamInfo->channelCount;
|
||||||
audioProperties->sampleRate = *bestStreamInfo->sampleRate;
|
audioProperties->sampleRate = *bestStreamInfo->sampleRate;
|
||||||
audioProperties->bitsPerSample = bestStreamInfo->bitsPerSample;
|
audioProperties->bitsPerSample = bestStreamInfo->bitsPerSample;
|
||||||
|
|||||||
Reference in New Issue
Block a user