4 #include "../vorbis/vorbiscomment.h" 6 #include "../exceptions.h" 7 #include "../mediafileinfo.h" 8 #include "../mediaformat.h" 10 #include "resources/config.h" 12 #include <c++utilities/io/copy.h> 33 FlacStream::FlacStream(
MediaFileInfo &mediaFileInfo, uint64 startOffset)
35 , m_mediaFileInfo(mediaFileInfo)
48 if (!m_vorbisComment) {
49 m_vorbisComment = make_unique<VorbisComment>();
51 return m_vorbisComment.get();
60 if (!m_vorbisComment) {
63 m_vorbisComment.reset();
69 static const string context(
"parsing raw FLAC header");
78 if (
m_reader.readUInt32BE() != 0x664C6143) {
88 header.parseHeader(buffer);
94 switch (static_cast<FlacMetaDataBlockType>(header.type())) {
96 if (header.dataSize() >= 0x22) {
99 streamInfo.
parse(buffer);
106 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_STREAMINFO\" is truncated and will be ignored.", context);
113 if (!m_vorbisComment) {
114 m_vorbisComment = make_unique<VorbisComment>();
133 diag.emplace_back(
DiagLevel::Warning,
"\"METADATA_BLOCK_PICTURE\" contains no picture.", context);
136 if (!m_vorbisComment) {
138 m_vorbisComment = make_unique<VorbisComment>();
141 m_vorbisComment->fields().insert(make_pair(coverField.
id(), move(coverField)));
145 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_PICTURE\" is truncated and will be ignored.", context);
150 m_paddingSize += 4 + header.dataSize();
162 m_streamOffset =
static_cast<uint32
>(
m_istream->tellg());
179 istream &originalStream = m_mediaFileInfo.
stream();
180 originalStream.seekg(static_cast<streamoff>(
m_startOffset + 4));
184 BE::getBytes(static_cast<uint32>(0x664C6143u), copy.buffer());
187 std::streamoff lastStartOffset = -1;
194 originalStream.read(copy.buffer(), 4);
198 switch (static_cast<FlacMetaDataBlockType>(header.
type())) {
203 originalStream.seekg(header.
dataSize(), ios_base::cur);
207 originalStream.seekg(-4, ios_base::cur);
210 lastActuallyWrittenHeader = header;
212 }
while (!header.
isLast());
215 if (lastStartOffset >= 4
216 && ((!m_vorbisComment && !lastActuallyWrittenHeader.
isLast()) || (m_vorbisComment && lastActuallyWrittenHeader.
isLast()))) {
218 lastActuallyWrittenHeader.
setLast(!m_vorbisComment);
220 originalStream.seekg(lastActuallyWrittenHeader.
dataSize(), ios_base::cur);
224 if (!m_vorbisComment) {
225 return lastStartOffset >= 0 ?
static_cast<uint32
>(lastStartOffset) : 0;
240 auto dataSize(static_cast<uint64>(endOffset) - static_cast<uint64>(lastStartOffset) - 4);
241 if (dataSize > 0xFFFFFF) {
243 diag.emplace_back(
DiagLevel::Critical,
"Vorbis Comment is too big and will be truncated.",
"write Vorbis Comment to FLAC stream");
246 header.
setLast(!m_vorbisComment->hasField(coverId));
249 outputStream.seekp(static_cast<streamoff>(dataSize), ios_base::cur);
250 lastActuallyWrittenHeader = header;
254 return static_cast<uint32
>(lastStartOffset);
257 const auto coverFields = m_vorbisComment->fields().equal_range(coverId);
258 for (
auto i = coverFields.first; i != coverFields.second;) {
266 header.
setLast(++i == coverFields.second);
271 lastStartOffset = lastCoverStartOffset;
272 lastActuallyWrittenHeader = header;
277 diag.emplace_back(
DiagLevel::Critical,
"Unable to serialize \"METADATA_BLOCK_PICTURE\" from assigned value.",
278 "write \"METADATA_BLOCK_PICTURE\" to FLAC stream");
285 if (!lastActuallyWrittenHeader.
isLast()) {
287 lastActuallyWrittenHeader.
setLast(
true);
292 return static_cast<uint32
>(lastStartOffset);
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
IoUtilities::BinaryReader m_reader
void setTypeInfo(const TypeInfoType &typeInfo)
Sets the type info of the current TagField.
bool removeVorbisComment()
Removes the assigned Vorbis comment if one is assigned; does nothing otherwise.
std::ostream & outputStream()
Returns the associated output stream.
bool isEmpty() const
Returns an indication whether an value is assigned.
uint32 makeHeader(std::ostream &stream, Diagnostics &diag)
Writes the FLAC metadata header to the specified outputStream.
Contains utility classes helping to read and write streams.
uint64 startOffset() const
Returns the start offset of the track in the associated stream.
ChronoUtilities::TimeSpan m_duration
void internalParseHeader(Diagnostics &diag) override
This method is internally called to parse header information.
uint64 size() const
Returns the size in bytes if known; otherwise returns 0.
The exception that is thrown when the data to be parsed holds no parsable information.
VorbisComment * createVorbisComment()
Creates a new Vorbis comment for the stream.
const IdentifierType & id() const
Returns the id of the current TagField.
static void makePadding(std::ostream &stream, uint32 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...
IoUtilities::NativeFileStream & stream()
Returns the std::fstream for the current instance.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
The TagValue class wraps values of different types.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
uint32 m_samplingFrequency
Contains all classes and functions of the TagInfo library.
void setId(const IdentifierType &id)
Sets the id of the current Tag Field.
The Diagnostics class is a container for DiagMessage.
TagValue & value()
Returns the value of the current TagField.