10#include "resources/config.h"
12#include <c++utilities/io/copy.h>
33 , m_mediaFileInfo(mediaFileInfo)
46 if (!m_vorbisComment) {
47 m_vorbisComment = make_unique<VorbisComment>();
49 return m_vorbisComment.get();
58 if (!m_vorbisComment) {
61 m_vorbisComment.reset();
67 CPP_UTILITIES_UNUSED(progress)
69 static const string context(
"parsing raw FLAC header");
75 constexpr auto bufferSize = 0x22;
76 char buffer[bufferSize];
79 if (
m_reader.readUInt32BE() != 0x664C6143) {
89 header.parseHeader(std::string_view(buffer, 4));
97 if (header.dataSize() >= bufferSize) {
100 streamInfo.
parse(std::string_view(buffer, bufferSize));
107 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_STREAMINFO\" is truncated and will be ignored.", context);
114 if (!m_vorbisComment) {
115 m_vorbisComment = make_unique<VorbisComment>();
122 m_vorbisComment->parse(*
m_istream, header.dataSize(),
flags, diag);
138 diag.emplace_back(
DiagLevel::Warning,
"\"METADATA_BLOCK_PICTURE\" contains no picture.", context);
141 if (!m_vorbisComment) {
143 m_vorbisComment = make_unique<VorbisComment>();
146 m_vorbisComment->fields().insert(make_pair(coverField.
id(), std::move(coverField)));
150 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_PICTURE\" is truncated and will be ignored.", context);
155 m_paddingSize += 4 + header.dataSize();
167 m_streamOffset =
static_cast<std::uint32_t
>(
m_istream->tellg());
183 istream &originalStream = m_mediaFileInfo.
stream();
184 originalStream.seekg(
static_cast<streamoff
>(
m_startOffset + 4));
185 CopyHelper<512> copy;
188 BE::getBytes(
static_cast<std::uint32_t
>(0x664C6143u), copy.buffer());
191 std::streamoff lastStartOffset = -1;
198 originalStream.read(copy.buffer(), 4);
199 header.
parseHeader(std::string_view(copy.buffer(), 4));
207 originalStream.seekg(header.
dataSize(), ios_base::cur);
211 originalStream.seekg(-4, ios_base::cur);
214 lastActuallyWrittenHeader = header;
216 }
while (!header.
isLast());
219 if (lastStartOffset >= 4
220 && ((!m_vorbisComment && !lastActuallyWrittenHeader.
isLast()) || (m_vorbisComment && lastActuallyWrittenHeader.
isLast()))) {
222 lastActuallyWrittenHeader.
setLast(!m_vorbisComment);
224 originalStream.seekg(lastActuallyWrittenHeader.
dataSize(), ios_base::cur);
228 if (!m_vorbisComment) {
229 return lastStartOffset >= 0 ? lastStartOffset : 0;
244 auto dataSize(
static_cast<std::uint64_t
>(endOffset) -
static_cast<std::uint64_t
>(lastStartOffset) - 4);
245 if (dataSize > 0xFFFFFF) {
247 diag.emplace_back(
DiagLevel::Critical,
"Vorbis Comment is too big and will be truncated.",
"write Vorbis Comment to FLAC stream");
249 header.
setDataSize(
static_cast<std::uint32_t
>(dataSize));
250 header.
setLast(!m_vorbisComment->hasField(coverId));
253 outputStream.seekp(
static_cast<streamoff
>(dataSize), ios_base::cur);
254 lastActuallyWrittenHeader = header;
258 return lastStartOffset;
261 const auto coverFields = m_vorbisComment->fields().equal_range(coverId);
262 for (
auto i = coverFields.first; i != coverFields.second;) {
270 header.
setLast(++i == coverFields.second);
275 lastStartOffset = lastCoverStartOffset;
276 lastActuallyWrittenHeader = header;
281 diag.emplace_back(
DiagLevel::Critical,
"Unable to serialize \"METADATA_BLOCK_PICTURE\" from assigned value.",
282 "write \"METADATA_BLOCK_PICTURE\" to FLAC stream");
289 if (!lastActuallyWrittenHeader.
isLast()) {
291 lastActuallyWrittenHeader.
setLast(
true);
296 return lastStartOffset;
305 CPP_UTILITIES_UNUSED(diag)
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
std::uint64_t size() const
Returns the size in bytes if known; otherwise returns 0.
std::uint64_t m_sampleCount
std::uint64_t startOffset() const
Returns the start offset of the track in the associated stream.
std::uint16_t m_bitsPerSample
std::uint16_t m_channelCount
CppUtilities::TimeSpan m_duration
CppUtilities::BinaryReader m_reader
std::uint64_t m_startOffset
TrackFlags flags() const
Returns flags (various boolean properties) of this track.
std::ostream & outputStream()
Returns the associated output stream.
std::uint32_t m_samplingFrequency
CppUtilities::NativeFileStream & stream()
Returns the std::fstream for the current instance.
The Diagnostics class is a container for DiagMessage.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
VorbisComment * createVorbisComment()
Creates a new Vorbis comment for the stream.
FlacStream(MediaFileInfo &mediaFileInfo, std::uint64_t startOffset)
Constructs a new track for the specified mediaFileInfo at the specified startOffset.
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override
This method is internally called to parse header information.
bool removeVorbisComment()
Removes the assigned Vorbis comment if one is assigned; does nothing otherwise.
std::streamoff makeHeader(std::ostream &stream, Diagnostics &diag)
Writes the FLAC metadata header to the specified outputStream.
static void makePadding(std::ostream &stream, std::uint32_t size, bool isLast, Diagnostics &diag)
Writes padding of the specified size to the specified stream.
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
The exception that is thrown when the data to be parsed holds no parsable information (e....
void setTypeInfo(const TypeInfoType &typeInfo)
Sets the type info of the current TagField.
IdentifierType & id()
Returns the id of the current TagField.
void setId(const IdentifierType &id)
Sets the id of the current Tag Field.
TagValue & value()
Returns the value of the current TagField.
The TagValue class wraps values of different types.
bool isEmpty() const
Returns whether no or an empty value is assigned.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Contains all classes and functions of the TagInfo library.
FlacMetaDataBlockType
The FlacMetaDataBlockType enum specifies the type of FlacMetaDataBlockHeader.