7 #include "../avi/bitmapinfoheader.h" 9 #include "../wav/waveaudiostream.h" 11 #include "../avc/avcconfiguration.h" 13 #include "../mp4/mp4ids.h" 14 #include "../mp4/mp4track.h" 16 #include "../exceptions.h" 17 #include "../mediaformat.h" 19 #include <c++utilities/conversion/stringconversion.h> 38 :
AbstractTrack(trackElement.stream(), trackElement.startOffset())
39 , m_trackElement(&trackElement)
62 const auto &part1 = parts[0], &part2 = parts[1], &part3 = parts[2];
64 if (part1 ==
"V_MS" && part2 ==
"VFW" && part3 ==
"FOURCC") {
66 }
else if (part1 ==
"V_UNCOMPRESSED") {
68 }
else if (part1 ==
"V_MPEG4") {
73 }
else if (part3 ==
"ASP") {
75 }
else if (part3 ==
"AVC") {
78 }
else if (part2 ==
"MS" && part3 ==
"V3") {
81 }
else if (part1 ==
"V_MPEG1") {
83 }
else if (part1 ==
"V_MPEG2") {
85 }
else if (part1 ==
"V_REAL") {
87 }
else if (part1 ==
"V_QUICKTIME") {
89 }
else if (part1 ==
"V_THEORA") {
91 }
else if (part1 ==
"V_PRORES") {
93 }
else if (part1 ==
"V_VP8") {
95 }
else if (part1 ==
"V_VP9") {
97 }
else if (part1 ==
"V_AV1") {
99 }
else if (part1 ==
"A_MPEG") {
103 }
else if (part2 ==
"L2") {
105 }
else if (part2 ==
"L3") {
108 }
else if (part1 ==
"V_MPEGH" && part2 ==
"ISO" && part3 ==
"HEVC") {
110 }
else if (part1 ==
"A_PCM") {
112 if (part2 ==
"INT") {
113 if (part3 ==
"BIG") {
115 }
else if (part3 ==
"LIT") {
118 }
else if (part2 ==
"FLOAT" && part3 ==
"IEEE") {
121 }
else if (part1 ==
"A_MPC") {
123 }
else if (part1 ==
"A_AC3") {
125 }
else if (part1 ==
"A_ALAC") {
127 }
else if (part1 ==
"A_DTS") {
129 if (part2 ==
"EXPRESS") {
131 }
else if (part2 ==
"LOSSLESS") {
134 }
else if (part1 ==
"A_VORBIS") {
136 }
else if (part1 ==
"A_FLAC") {
138 }
else if (part1 ==
"A_OPUS") {
140 }
else if (part1 ==
"A_REAL") {
142 }
else if (part1 ==
"A_MS" && part2 ==
"ACM") {
144 }
else if (part1 ==
"A_AAC") {
146 if (part2 ==
"MPEG2") {
147 if (part3 ==
"MAIN") {
149 }
else if (part3 ==
"LC") {
151 }
else if (part3 ==
"SBR") {
154 }
else if (part3 ==
"SSR") {
157 }
else if (part2 ==
"MPEG4") {
158 if (part3 ==
"MAIN") {
160 }
else if (part3 ==
"LC") {
162 }
else if (part3 ==
"SBR") {
165 }
else if (part3 ==
"SSR") {
167 }
else if (part3 ==
"LTP") {
171 }
else if (part1 ==
"A_QUICKTIME") {
173 }
else if (part1 ==
"A_TTA1") {
175 }
else if (part1 ==
"A_WAVPACK4") {
177 }
else if (part1 ==
"S_TEXT") {
179 if (part2 ==
"UTF8") {
181 }
else if (part2 ==
"SSA") {
183 }
else if (part2 ==
"ASS") {
185 }
else if (part2 ==
"USF") {
187 }
else if (part2 ==
"WEBVTT") {
190 }
else if (part1 ==
"S_IMAGE") {
192 if (part2 ==
"BMP") {
195 }
else if (part1 ==
"S_VOBSUB") {
197 }
else if (part1 ==
"S_KATE") {
199 }
else if (part1 ==
"B_VOBBTN") {
201 }
else if (part1 ==
"S_DVBSUB") {
203 }
else if (part1 ==
"V_MSWMV") {
211 template <
typename PropertyType,
typename ConversionFunction>
212 void MatroskaTrack::assignPropertyFromTagValue(
const std::unique_ptr<MatroskaTag> &tag,
const char *fieldId, PropertyType &property,
213 const ConversionFunction &conversionFunction,
Diagnostics &diag)
215 const TagValue &value = tag->value(fieldId);
218 property = conversionFunction(value);
219 }
catch (
const ConversionException &) {
223 }
catch (
const ConversionException &) {
224 message = argsToString(
"Ignoring invalid value of \"", fieldId,
'\"',
'.');
226 diag.emplace_back(
DiagLevel::Warning, message, argsToString(
"reading track statatistic from \"", tag->toString(),
'\"'));
231 template <
typename NumberType, Traits::EnableIf<std::is_
integral<NumberType>> * =
nullptr> NumberType tagValueToNumber(
const TagValue &tagValue)
235 switch (tagValue.dataEncoding()) {
238 return bufferToNumber<NumberType>(tagValue.dataPointer(), tagValue.dataSize());
246 template <
typename NumberType, Traits::EnableIf<std::is_
floating_po
int<NumberType>> * =
nullptr>
247 NumberType tagValueToBitrate(
const TagValue &tagValue)
266 using namespace MatroskaTagIds::TrackSpecific;
267 for (
const auto &tag : tags) {
285 static const string context(
"parsing header of Matroska track");
287 m_trackElement->parse(diag);
293 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
294 trackInfoElement = trackInfoElement->nextSibling()) {
296 trackInfoElement->parse(diag);
298 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
301 uint32 defaultDuration = 0;
302 switch (trackInfoElement->id()) {
304 switch (trackInfoElement->readUInteger()) {
325 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
327 subElement->parse(diag);
332 switch (subElement->id()) {
358 m_fps = subElement->readFloat();
371 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
373 subElement->parse(diag);
378 switch (subElement->id()) {
403 m_id = trackInfoElement->readUInteger();
406 m_name = trackInfoElement->readString();
420 m_enabled = trackInfoElement->readUInteger();
423 m_default = trackInfoElement->readUInteger();
426 m_forced = trackInfoElement->readUInteger();
429 m_lacing = trackInfoElement->readUInteger();
432 defaultDuration = trackInfoElement->readUInteger();
438 if (!
m_fps && defaultDuration) {
439 m_fps = 1000000000.0 / defaultDuration;
452 if (codecPrivateElement->
dataSize() >= 0x28) {
462 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
469 if (codecPrivateElement->
dataSize() >= 16) {
475 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
481 auto audioSpecificConfig
484 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
485 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
490 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
492 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
497 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
505 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
567 if (!m_track.name().empty()) {
570 if (!m_track.language().empty()) {
575 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
576 switch (trackInfoElement->id()) {
587 trackInfoElement->makeBuffer();
588 m_dataSize += trackInfoElement->totalSize();
592 m_requiredSize = 1 + m_sizeDenotationLength + m_dataSize;
608 stream.write(buffer, 1 + m_sizeDenotationLength);
616 if (!m_track.
name().empty()) {
624 for (
EbmlElement *trackInfoElement = m_track.m_trackElement->
firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
625 switch (trackInfoElement->id()) {
636 trackInfoElement->copyBuffer(stream);
const std::string & language() const
Returns the language of the track if known; otherwise returns an empty string.
constexpr TAG_PARSER_EXPORT const char * numberOfBytes()
void setBottom(uint32 bottom)
Sets the bottom margin to bottom.
bool isDefault() const
Returns true if the track is denoted as default; otherwise returns false.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
IoUtilities::BinaryReader m_reader
const std::string name() const
Returns the track name if known; otherwise returns an empty string.
byte m_extensionChannelConfig
uint32 trackNumber() const
Returns the track number if known; otherwise returns 0.
static void makeSimpleElement(std::ostream &stream, IdentifierType id, uint64 content)
Makes a simple EBML element.
void setWidth(uint32 value)
Sets the width.
ImplementationType * firstChild()
Returns the first child of the element.
constexpr TAG_PARSER_EXPORT const char * numberOfFrames()
static MediaFormat codecIdToMediaFormat(const std::string &codecId)
Returns the MediaFormat for the specified Matroska codec ID.
static byte calculateSizeDenotationLength(uint64 size)
Returns the length of the size denotation for the specified size in byte.
static void addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track)
Adds the information from the specified avcConfig to the specified track.
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
DataSizeType dataSize() const
Returns the data size of the element in byte.
IoUtilities::BinaryReader & reader()
Returns a binary reader for the associated stream.
uint32 m_extensionSamplingFrequency
void setLeft(uint32 left)
Sets the left margin to left.
static byte calculateUIntegerLength(uint64 integer)
Returns the length of the specified unsigned integer in byte.
The EbmlElement class helps to parse EBML files such as Matroska files.
static std::unique_ptr< Mpeg4AudioSpecificConfig > parseAudioSpecificConfig(std::istream &stream, uint64 startOffset, uint64 size, Diagnostics &diag)
Parses the audio specific configuration for the track.
~MatroskaTrack() override
Destroys the track.
void setRight(uint32 right)
Sets the right margin to right.
void setHeight(uint32 value)
Sets the height.
TAG_PARSER_EXPORT MediaFormat idToMediaFormat(byte mpeg4AudioObjectId, bool sbrPresent=false, bool psPresent=false)
bool isEmpty() const
Returns an indication whether an value is assigned.
uint64 dataOffset() const
Returns the data offset of the element in the related stream.
ChronoUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
constexpr uint32 height() const
Returns the height.
void internalParseHeader(Diagnostics &diag) override
This method is internally called to parse header information.
ChronoUtilities::TimeSpan m_duration
void setTop(uint32 top)
Sets the top margin to top.
static byte makeSizeDenotation(uint64 size, char *buff)
Makes the size denotation for the specified size and stores it to buff.
The TagTarget class specifies the target of a tag.
TAG_PARSER_EXPORT MediaFormat fourccToMediaFormat(uint32 fourccId)
constexpr TAG_PARSER_EXPORT const char * bitrate()
The track's bit rate in bits per second.
constexpr TAG_PARSER_EXPORT const char * duration()
bool isEnabled() const
Returns true if the track is denoted as enabled; otherwise returns false.
uint64 id() const
Returns the track ID if known; otherwise returns 0.
ChronoUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation.
ChronoUtilities::DateTime m_creationTime
const IdContainerType & tracks() const
Returns the tracks.
Implementation of TagParser::AbstractTrack for the Matroska container.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified. ...
bool isForced() const
Returns true if the track is denoted as forced; otherwise returns false.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
ChronoUtilities::DateTime m_modificationTime
constexpr uint32 width() const
Returns the width.
The TagValue class wraps values of different types.
void readStatisticsFromTags(const std::vector< std::unique_ptr< MatroskaTag >> &tags, Diagnostics &diag)
Reads track-specific statistics from the specified tags.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
uint32 m_samplingFrequency
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
Contains all classes and functions of the TagInfo library.
TrackType
Specifies the track type.
constexpr TAG_PARSER_EXPORT const char * writingDate()
The Diagnostics class is a container for DiagMessage.
uint32 mpeg4SamplingFrequencyTable[13]