Exposed metadata for each embedded picture
This commit is contained in:
@@ -34,6 +34,8 @@ extern "C"
|
|||||||
#include "core/ILogger.hpp"
|
#include "core/ILogger.hpp"
|
||||||
#include "core/String.hpp"
|
#include "core/String.hpp"
|
||||||
|
|
||||||
|
#include "av/Types.hpp"
|
||||||
|
|
||||||
namespace lms::av
|
namespace lms::av
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
@@ -43,9 +45,9 @@ namespace lms::av
|
|||||||
std::array<char, 128> buf = { 0 };
|
std::array<char, 128> buf = { 0 };
|
||||||
|
|
||||||
if (::av_strerror(error, buf.data(), buf.size()) == 0)
|
if (::av_strerror(error, buf.data(), buf.size()) == 0)
|
||||||
return &buf[0];
|
return buf.data();
|
||||||
else
|
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
class AudioFileException : public Exception
|
class AudioFileException : public Exception
|
||||||
@@ -158,7 +160,7 @@ namespace lms::av
|
|||||||
{
|
{
|
||||||
ContainerInfo info;
|
ContainerInfo info;
|
||||||
info.bitrate = _context->bit_rate;
|
info.bitrate = _context->bit_rate;
|
||||||
info.duration = std::chrono::milliseconds{ _context->duration == AV_NOPTS_VALUE ? 0 : _context->duration / AV_TIME_BASE * 1000 };
|
info.duration = std::chrono::milliseconds{ _context->duration == AV_NOPTS_VALUE ? 0 : _context->duration / AV_TIME_BASE * 1'000 };
|
||||||
info.name = _context->iformat->name;
|
info.name = _context->iformat->name;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
@@ -237,7 +239,7 @@ namespace lms::av
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFile::visitAttachedPictures(std::function<void(const Picture&)> func) const
|
void AudioFile::visitAttachedPictures(std::function<void(const Picture&, const MetadataMap&)> func) const
|
||||||
{
|
{
|
||||||
static const std::unordered_map<int, std::string> codecMimeMap{
|
static const std::unordered_map<int, std::string> codecMimeMap{
|
||||||
{ AV_CODEC_ID_BMP, "image/x-bmp" },
|
{ AV_CODEC_ID_BMP, "image/x-bmp" },
|
||||||
@@ -262,6 +264,9 @@ namespace lms::av
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetadataMap metadata;
|
||||||
|
getMetaDataFromDictionnary(avstream->metadata, metadata);
|
||||||
|
|
||||||
Picture picture;
|
Picture picture;
|
||||||
|
|
||||||
auto itMime = codecMimeMap.find(avstream->codecpar->codec_id);
|
auto itMime = codecMimeMap.find(avstream->codecpar->codec_id);
|
||||||
@@ -280,7 +285,7 @@ namespace lms::av
|
|||||||
picture.data = reinterpret_cast<const std::byte*>(pkt.data);
|
picture.data = reinterpret_cast<const std::byte*>(pkt.data);
|
||||||
picture.dataSize = pkt.size;
|
picture.dataSize = pkt.size;
|
||||||
|
|
||||||
func(picture);
|
func(picture, metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ struct AVFormatContext;
|
|||||||
|
|
||||||
namespace lms::av
|
namespace lms::av
|
||||||
{
|
{
|
||||||
|
|
||||||
class AudioFile final : public IAudioFile
|
class AudioFile final : public IAudioFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AudioFile(const std::filesystem::path& p);
|
AudioFile(const std::filesystem::path& p);
|
||||||
~AudioFile();
|
~AudioFile() override;
|
||||||
|
AudioFile(const AudioFile&) = delete;
|
||||||
|
AudioFile& operator=(const AudioFile&) = delete;
|
||||||
|
|
||||||
const std::filesystem::path& getPath() const override;
|
const std::filesystem::path& getPath() const override;
|
||||||
ContainerInfo getContainerInfo() const override;
|
ContainerInfo getContainerInfo() const override;
|
||||||
@@ -39,16 +40,12 @@ namespace lms::av
|
|||||||
std::optional<StreamInfo> getBestStreamInfo() const override;
|
std::optional<StreamInfo> getBestStreamInfo() const override;
|
||||||
std::optional<std::size_t> getBestStreamIndex() const override;
|
std::optional<std::size_t> getBestStreamIndex() const override;
|
||||||
bool hasAttachedPictures() const override;
|
bool hasAttachedPictures() const override;
|
||||||
void visitAttachedPictures(std::function<void(const Picture&)> func) const override;
|
void visitAttachedPictures(std::function<void(const Picture&, const MetadataMap&)> func) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioFile(const AudioFile&) = delete;
|
|
||||||
AudioFile& operator=(const AudioFile&) = delete;
|
|
||||||
|
|
||||||
std::optional<StreamInfo> getStreamInfo(std::size_t streamIndex) const;
|
std::optional<StreamInfo> getStreamInfo(std::size_t streamIndex) const;
|
||||||
|
|
||||||
const std::filesystem::path _p;
|
const std::filesystem::path _p;
|
||||||
AVFormatContext* _context{};
|
AVFormatContext* _context{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lms::av
|
} // namespace lms::av
|
||||||
|
|||||||
@@ -28,8 +28,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Types.hpp"
|
|
||||||
|
|
||||||
namespace lms::av
|
namespace lms::av
|
||||||
{
|
{
|
||||||
// List should be sync with the codecs shipped in the lms's docker version
|
// List should be sync with the codecs shipped in the lms's docker version
|
||||||
@@ -62,14 +60,14 @@ namespace lms::av
|
|||||||
struct Picture
|
struct Picture
|
||||||
{
|
{
|
||||||
std::string mimeType;
|
std::string mimeType;
|
||||||
const std::byte* data{};
|
const std::byte* data{}; // valid as long as IAudioFile exists
|
||||||
std::size_t dataSize{};
|
std::size_t dataSize{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContainerInfo
|
struct ContainerInfo
|
||||||
{
|
{
|
||||||
std::size_t bitrate{};
|
std::size_t bitrate{};
|
||||||
std::string name{};
|
std::string name;
|
||||||
std::chrono::milliseconds duration{};
|
std::chrono::milliseconds duration{};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ namespace lms::av
|
|||||||
virtual std::optional<StreamInfo> getBestStreamInfo() const = 0; // none if failure/unknown
|
virtual std::optional<StreamInfo> getBestStreamInfo() const = 0; // none if failure/unknown
|
||||||
virtual std::optional<std::size_t> getBestStreamIndex() const = 0; // none if failure/unknown
|
virtual std::optional<std::size_t> getBestStreamIndex() const = 0; // none if failure/unknown
|
||||||
virtual bool hasAttachedPictures() const = 0;
|
virtual bool hasAttachedPictures() const = 0;
|
||||||
virtual void visitAttachedPictures(std::function<void(const Picture&)> func) const = 0;
|
virtual void visitAttachedPictures(std::function<void(const Picture&, const MetadataMap& metadata)> func) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IAudioFile> parseAudioFile(const std::filesystem::path& p);
|
std::unique_ptr<IAudioFile> parseAudioFile(const std::filesystem::path& p);
|
||||||
|
|||||||
@@ -20,11 +20,9 @@
|
|||||||
#include "ArtworkService.hpp"
|
#include "ArtworkService.hpp"
|
||||||
|
|
||||||
#include "av/IAudioFile.hpp"
|
#include "av/IAudioFile.hpp"
|
||||||
|
#include "av/Types.hpp"
|
||||||
#include "core/IConfig.hpp"
|
#include "core/IConfig.hpp"
|
||||||
#include "core/ILogger.hpp"
|
#include "core/ILogger.hpp"
|
||||||
#include "core/Path.hpp"
|
|
||||||
#include "core/Random.hpp"
|
|
||||||
#include "core/String.hpp"
|
|
||||||
#include "core/Utils.hpp"
|
#include "core/Utils.hpp"
|
||||||
#include "database/Artist.hpp"
|
#include "database/Artist.hpp"
|
||||||
#include "database/Db.hpp"
|
#include "database/Db.hpp"
|
||||||
@@ -71,7 +69,7 @@ namespace lms::cover
|
|||||||
{
|
{
|
||||||
std::unique_ptr<IEncodedImage> image;
|
std::unique_ptr<IEncodedImage> image;
|
||||||
|
|
||||||
input.visitAttachedPictures([&](const av::Picture& picture) {
|
input.visitAttachedPictures([&](const av::Picture& picture, const av::IAudioFile::MetadataMap& /* metadata */) {
|
||||||
if (image)
|
if (image)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user