Tag Parser 12.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
mp4atom.cpp
Go to the documentation of this file.
1#include "./mp4atom.h"
2#include "./mp4container.h"
3#include "./mp4ids.h"
4#include "./mp4tag.h"
5#include "./mp4track.h"
6
7#include "../exceptions.h"
8#include "../mediafileinfo.h"
9
10#include <c++utilities/conversion/stringbuilder.h>
11#include <c++utilities/io/binaryreader.h>
12#include <c++utilities/io/binarywriter.h>
13
14#include <sstream>
15
16using namespace std;
17using namespace CppUtilities;
18
19namespace TagParser {
20
29Mp4Atom::Mp4Atom(GenericFileElement::ContainerType &container, std::uint64_t startOffset)
30 : GenericFileElement<Mp4Atom>(container, startOffset)
31{
32}
33
37Mp4Atom::Mp4Atom(GenericFileElement::ContainerType &container, std::uint64_t startOffset, std::uint64_t maxSize)
38 : GenericFileElement<Mp4Atom>(container, startOffset, maxSize)
39{
40}
41
45Mp4Atom::Mp4Atom(Mp4Atom &parent, std::uint64_t startOffset)
46 : GenericFileElement<Mp4Atom>(parent, startOffset)
47{
48}
49
53string Mp4Atom::parsingContext() const
54{
55 return "parsing " % idToString() % " atom at " + startOffset();
56}
57
62{
63 static const string context("parsing MP4 atom");
65 diag.emplace_back(DiagLevel::Critical,
66 argsToString("Atom is smaller than 8 byte and hence invalid. The remaining size within the parent atom is ", maxTotalSize(), '.'),
67 context);
69 }
70 stream().seekg(static_cast<streamoff>(startOffset()));
71 m_dataSize = reader().readUInt32BE();
72 if (m_dataSize == 0) {
73 // atom size extends to rest of the file/enclosing container
75 }
76 if (!m_dataSize) {
77 diag.emplace_back(DiagLevel::Critical, "No data found (only null bytes).", context);
79 }
80 if (m_dataSize < 8 && m_dataSize != 1) {
81 diag.emplace_back(DiagLevel::Critical, "Atom is smaller than 8 byte and hence invalid.", context);
83 }
84 m_id = reader().readUInt32BE();
85 m_idLength = 4;
86 if (m_dataSize == 1) { // atom denotes 64-bit size
87 m_dataSize = reader().readUInt64BE();
88 m_sizeLength = 12; // 4 bytes indicate long size denotation + 8 bytes for actual size denotation
89 if (dataSize() < 16 && m_dataSize != 1) {
90 diag.emplace_back(DiagLevel::Critical, "Atom denoting 64-bit size is smaller than 16 byte and hence invalid.", parsingContext());
92 }
93 } else {
94 m_sizeLength = 4;
95 }
96 if (maxTotalSize() < m_dataSize) { // currently m_dataSize holds data size plus header size!
97 diag.emplace_back(DiagLevel::Warning, "The atom seems to be truncated; unable to parse siblings of that ", parsingContext());
98 m_dataSize = maxTotalSize(); // using max size instead
99 }
100 // currently m_dataSize holds data size plus header size!
102 Mp4Atom *child = nullptr;
103 if (std::uint64_t firstChildOffset = this->firstChildOffset()) {
105 child = new Mp4Atom(static_cast<Mp4Atom &>(*this), startOffset() + firstChildOffset);
106 }
107 }
108 m_firstChild.reset(child);
109 Mp4Atom *sibling = nullptr;
110 if (totalSize() < maxTotalSize()) {
111 if (parent()) {
112 sibling = new Mp4Atom(*(parent()), startOffset() + totalSize());
113 } else {
114 sibling = new Mp4Atom(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
115 }
116 }
117 m_nextSibling.reset(sibling);
118}
119
133void Mp4Atom::seekBackAndWriteAtomSize(std::ostream &stream, const std::ostream::pos_type &startOffset, Diagnostics &diag)
134{
135 ostream::pos_type currentOffset = stream.tellp();
136 const auto atomSize(currentOffset - startOffset);
137 if (atomSize > numeric_limits<std::uint32_t>::max()) {
138 diag.emplace_back(DiagLevel::Fatal, argsToString(atomSize, " exceeds maximum."), "write 32-bit atom size");
139 throw Failure();
140 }
141 stream.seekp(startOffset);
142 BinaryWriter writer(&stream);
143 writer.writeUInt32BE(static_cast<std::uint32_t>(atomSize));
144 stream.seekp(currentOffset);
145}
146
157void Mp4Atom::seekBackAndWriteAtomSize64(std::ostream &stream, const ostream::pos_type &startOffset)
158{
159 ostream::pos_type currentOffset = stream.tellp();
160 stream.seekp(startOffset);
161 BinaryWriter writer(&stream);
162 writer.writeUInt32BE(1);
163 stream.seekp(4, ios_base::cur);
164 writer.writeUInt64BE(static_cast<std::uint64_t>(currentOffset - startOffset));
165 stream.seekp(currentOffset);
166}
167
171void Mp4Atom::makeHeader(std::uint64_t size, std::uint32_t id, BinaryWriter &writer)
172{
173 if (size < numeric_limits<std::uint32_t>::max()) {
174 writer.writeUInt32BE(static_cast<std::uint32_t>(size));
175 writer.writeUInt32BE(id);
176 } else {
177 writer.writeUInt32BE(1);
178 writer.writeUInt32BE(id);
179 writer.writeUInt64BE(size);
180 }
181}
182
191{
192 using namespace Mp4AtomIds;
193 // some atom ids are known to be parents
194 switch (id()) {
195 case Movie:
196 case Track:
197 case Edit:
198 case Media:
199 case MediaInformation:
200 case MediaInformationHeader:
201 case DataInformation:
202 case SampleTable:
203 case UserData:
204 case Meta:
205 case ItunesList:
206 case MovieFragment:
207 case TrackFragment:
208 case TrackReference:
209 case MovieExtends:
210 case DataReference:
214 case FourccIds::Amr:
215 case FourccIds::Drms:
216 case FourccIds::Alac:
218 case FourccIds::Ac3:
219 case FourccIds::EAc3:
221 case FourccIds::Dts:
222 case FourccIds::DtsH:
223 case FourccIds::DtsE:
224 return true;
225 default:
226 if (parent()) {
227 // some atom ids are known to contain parents
228 switch (parent()->id()) {
229 case ItunesList:
230 return true;
231 default:;
232 }
233 }
234 }
235 return false;
236}
237
245{
246 using namespace Mp4AtomIds;
247 switch (id()) {
248 case Free:
249 case Skip:
250 return true;
251 default:
252 return false;
253 }
254}
255
264std::uint64_t Mp4Atom::firstChildOffset() const
265{
266 using namespace Mp4AtomIds;
267 using namespace FourccIds;
268 if (isParent()) {
269 switch (id()) {
270 case Meta:
271 if (parent() && parent()->id() == Mp4AtomIds::UserData) {
272 return headerSize() + 0x4u;
273 }
274 return headerSize();
275 case DataReference:
276 return headerSize() + 0x8u;
277 default:
278 return headerSize();
279 }
280 } else {
281 switch (id()) {
282 case SampleDescription:
283 return headerSize() + 0x08u;
284 default:
285 return 0x00u;
286 }
287 }
288}
289
290} // namespace TagParser
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...
Definition exceptions.h:11
The GenericFileElement class helps to parse binary files which consist of an arboreal element structu...
std::uint64_t startOffset() const
Returns the start offset in the related stream.
std::uint32_t headerSize() const
Returns the header size of the element in byte.
CppUtilities::BinaryWriter & writer()
Returns the related BinaryWriter.
typename FileElementTraits< ImplementationType >::ContainerType ContainerType
Specifies the type of the corresponding container.
std::iostream & stream()
Returns the related stream.
Mp4Atom * parent()
Returns the parent of the element.
static constexpr std::uint8_t minimumElementSize()
Returns the minimum element size.
DataSizeType dataSize() const
Returns the data size of the element in byte.
std::uint64_t totalSize() const
Returns the total size of the element.
ContainerType & container()
Returns the related container.
CppUtilities::BinaryReader & reader()
Returns the related BinaryReader.
std::uint64_t maxTotalSize() const
Returns maximum total size.
The Mp4Atom class helps to parse MP4 files.
Definition mp4atom.h:38
std::string idToString() const
Converts the specified atom ID to a printable string.
Definition mp4atom.h:67
static void seekBackAndWriteAtomSize(std::ostream &stream, const std::ostream::pos_type &startOffset, Diagnostics &diag)
This function helps to write the atom size after writing an atom to a stream.
Definition mp4atom.cpp:133
static void makeHeader(std::uint64_t size, std::uint32_t id, CppUtilities::BinaryWriter &writer)
Writes an MP4 atom header to the specified stream.
Definition mp4atom.cpp:171
static void seekBackAndWriteAtomSize64(std::ostream &stream, const std::ostream::pos_type &startOffset)
This function helps to write the atom size after writing an atom to a stream.
Definition mp4atom.cpp:157
bool isParent() const
Returns an indication whether the atom is a parent element.
Definition mp4atom.cpp:190
void internalParse(Diagnostics &diag)
Parses the MP4 atom.
Definition mp4atom.cpp:61
std::uint64_t firstChildOffset() const
Returns the offset of the first child (relative to the start offset of this atom).
Definition mp4atom.cpp:264
bool isPadding() const
Returns an indication whether the atom is a padding element.
Definition mp4atom.cpp:244
Mp4Atom(ContainerType &container, std::uint64_t startOffset)
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition exceptions.h:18
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition exceptions.h:39
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10