Tag Parser: mp4/mp4atom.cpp Source File

Tag Parser 12.5.2 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
25
29 Mp4Atom::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
45 Mp4Atom::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
61 void Mp4Atom::internalParse(Diagnostics &diag)
62{
63 static const string context("parsing MP4 atom");
64 if (maxTotalSize() < minimumElementSize()) {
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);
68 throw TruncatedDataException();
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
74 m_dataSize = maxTotalSize();
75 }
76 if (!m_dataSize) {
77 diag.emplace_back(DiagLevel::Critical, "No data found (only null bytes).", context);
78 throw NoDataFoundException();
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);
82 throw TruncatedDataException();
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());
91 throw TruncatedDataException();
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!
101 m_dataSize -= headerSize();
102 Mp4Atom *child = nullptr;
103 if (std::uint64_t firstChildOffset = this->firstChildOffset()) {
104 if (firstChildOffset + minimumElementSize() <= totalSize()) {
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
133 void 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
157 void 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
171 void 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
190 bool Mp4Atom::isParent() const
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:
211 case Mp4AtomIds::AvcConfiguration:
212 case FourccIds::Mpeg4Audio:
213 case FourccIds::AmrNarrowband:
214 case FourccIds::Amr:
215 case FourccIds::Drms:
216 case FourccIds::Alac:
217 case FourccIds::WindowsMediaAudio:
218 case FourccIds::Ac3:
219 case FourccIds::EAc3:
220 case FourccIds::DolbyMpl:
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
244 bool Mp4Atom::isPadding() const
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
TagParser::Diagnostics
The Diagnostics class is a container for DiagMessage.
Definition diagnostics.h:156
TagParser::Failure
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition exceptions.h:11
TagParser::GenericFileElement
The GenericFileElement class helps to parse binary files which consist of an arboreal element structu...
Definition genericfileelement.h:44
TagParser::GenericFileElement< Mp4Atom >::GenericFileElement
GenericFileElement(ContainerType &container, std::uint64_t startOffset)
TagParser::GenericFileElement< Mp4Atom >::m_dataSize
DataSizeType m_dataSize
Definition genericfileelement.h:138
TagParser::GenericFileElement< Mp4Atom >::startOffset
std::uint64_t startOffset() const
Definition genericfileelement.h:266
TagParser::GenericFileElement< Mp4Atom >::m_idLength
std::uint32_t m_idLength
Definition genericfileelement.h:139
TagParser::GenericFileElement< Mp4Atom >::headerSize
std::uint32_t headerSize() const
Definition genericfileelement.h:309
TagParser::GenericFileElement< Mp4Atom >::writer
CppUtilities::BinaryWriter & writer()
Definition genericfileelement.h:258
TagParser::GenericFileElement::ContainerType
typename FileElementTraits< ImplementationType >::ContainerType ContainerType
Specifies the type of the corresponding container.
Definition genericfileelement.h:51
TagParser::GenericFileElement< Mp4Atom >::stream
std::iostream & stream()
Definition genericfileelement.h:242
TagParser::GenericFileElement< Mp4Atom >::m_nextSibling
std::unique_ptr< Mp4Atom > m_nextSibling
Definition genericfileelement.h:142
TagParser::GenericFileElement< Mp4Atom >::parent
Mp4Atom * parent()
Definition genericfileelement.h:390
TagParser::GenericFileElement< Mp4Atom >::minimumElementSize
static constexpr std::uint8_t minimumElementSize()
Definition genericfileelement.h:996
TagParser::GenericFileElement< Mp4Atom >::m_firstChild
std::unique_ptr< Mp4Atom > m_firstChild
Definition genericfileelement.h:143
TagParser::GenericFileElement< Mp4Atom >::m_id
IdentifierType m_id
Definition genericfileelement.h:135
TagParser::GenericFileElement< Mp4Atom >::dataSize
DataSizeType dataSize() const
Definition genericfileelement.h:320
TagParser::GenericFileElement< Mp4Atom >::totalSize
std::uint64_t totalSize() const
Definition genericfileelement.h:348
TagParser::GenericFileElement< Mp4Atom >::container
ContainerType & container()
Definition genericfileelement.h:225
TagParser::GenericFileElement< Mp4Atom >::reader
CppUtilities::BinaryReader & reader()
Definition genericfileelement.h:250
TagParser::GenericFileElement< Mp4Atom >::maxTotalSize
std::uint64_t maxTotalSize() const
Definition genericfileelement.h:367
TagParser::GenericFileElement< Mp4Atom >::m_sizeLength
std::uint32_t m_sizeLength
Definition genericfileelement.h:140
TagParser::Mp4Atom
The Mp4Atom class helps to parse MP4 files.
Definition mp4atom.h:38
TagParser::Mp4Atom::idToString
std::string idToString() const
Converts the specified atom ID to a printable string.
Definition mp4atom.h:67
TagParser::Mp4Atom::seekBackAndWriteAtomSize
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
TagParser::Mp4Atom::makeHeader
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
TagParser::Mp4Atom::seekBackAndWriteAtomSize64
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
TagParser::Mp4Atom::isParent
bool isParent() const
Returns an indication whether the atom is a parent element.
Definition mp4atom.cpp:190
TagParser::Mp4Atom::internalParse
void internalParse(Diagnostics &diag)
Parses the MP4 atom.
Definition mp4atom.cpp:61
TagParser::Mp4Atom::firstChildOffset
std::uint64_t firstChildOffset() const
Returns the offset of the first child (relative to the start offset of this atom).
Definition mp4atom.cpp:264
TagParser::Mp4Atom::isPadding
bool isPadding() const
Returns an indication whether the atom is a padding element.
Definition mp4atom.cpp:244
TagParser::Mp4Atom::Mp4Atom
Mp4Atom(ContainerType &container, std::uint64_t startOffset)
TagParser::NoDataFoundException
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition exceptions.h:18
TagParser::TruncatedDataException
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition exceptions.h:39
exceptions.h
mediafileinfo.h
mp4atom.h
mp4container.h
mp4ids.h
mp4tag.h
mp4track.h
CppUtilities
Definition abstractcontainer.h:16
TagParser::FourccIds
Encapsulates all supported MP4 media format IDs (aka "FOURCCs").
Definition mp4ids.h:161
TagParser::FourccIds::Mpeg4Audio
@ Mpeg4Audio
Definition mp4ids.h:343
TagParser::FourccIds::Alac
@ Alac
Definition mp4ids.h:167
TagParser::FourccIds::Amr
@ Amr
Definition mp4ids.h:172
TagParser::FourccIds::DolbyMpl
@ DolbyMpl
Definition mp4ids.h:335
TagParser::FourccIds::DtsH
@ DtsH
Definition mp4ids.h:277
TagParser::FourccIds::Drms
@ Drms
Definition mp4ids.h:274
TagParser::FourccIds::Ac3
@ Ac3
Definition mp4ids.h:163
TagParser::FourccIds::WindowsMediaAudio
@ WindowsMediaAudio
Definition mp4ids.h:409
TagParser::FourccIds::AmrNarrowband
@ AmrNarrowband
Definition mp4ids.h:173
TagParser::FourccIds::EAc3
@ EAc3
Definition mp4ids.h:283
TagParser::FourccIds::DtsE
@ DtsE
Definition mp4ids.h:278
TagParser::FourccIds::Dts
@ Dts
Definition mp4ids.h:276
TagParser::Mp4AtomIds
Encapsulates the most common MP4 atom IDs.
Definition mp4ids.h:14
TagParser::Mp4AtomIds::UserData
@ UserData
Definition mp4ids.h:77
TagParser::Mp4AtomIds::AvcConfiguration
@ AvcConfiguration
Definition mp4ids.h:17
TagParser
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
TagParser::TagTargetLevel::Track
@ Track
Definition tagtarget.h:16
TagParser::Mp4TagMediaType::Movie
@ Movie
Definition mp4ids.h:684
TagParser::DiagLevel::Warning
@ Warning
Definition diagnostics.h:20
TagParser::DiagLevel::Critical
@ Critical
Definition diagnostics.h:21
TagParser::DiagLevel::Fatal
@ Fatal
Definition diagnostics.h:22
TagParser::MediaType::Meta
@ Meta
Definition mediaformat.h:22