Tag Parser 12.3.1
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...
The GenericFileElement class helps to parse binary files which consist of an arboreal element structu...
CppUtilities::BinaryWriter & writer()
typename FileElementTraits< ImplementationType >::ContainerType ContainerType
Specifies the type of the corresponding container.
static constexpr std::uint8_t minimumElementSize()
CppUtilities::BinaryReader & reader()
The Mp4Atom class helps to parse MP4 files.
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....
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.
Definition aaccodebook.h:10