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 ==
"A_MPEG") {
101 }
else if (part2 ==
"L2") {
103 }
else if (part2 ==
"L3") {
106 }
else if (part1 ==
"V_MPEGH" && part2 ==
"ISO" && part3 ==
"HEVC") {
108 }
else if (part1 ==
"A_PCM") {
110 if (part2 ==
"INT") {
111 if (part3 ==
"BIG") {
113 }
else if (part3 ==
"LIT") {
116 }
else if (part2 ==
"FLOAT" && part3 ==
"IEEE") {
119 }
else if (part1 ==
"A_MPC") {
121 }
else if (part1 ==
"A_AC3") {
123 }
else if (part1 ==
"A_ALAC") {
125 }
else if (part1 ==
"A_DTS") {
127 if (part2 ==
"EXPRESS") {
129 }
else if (part2 ==
"LOSSLESS") {
132 }
else if (part1 ==
"A_VORBIS") {
134 }
else if (part1 ==
"A_FLAC") {
136 }
else if (part1 ==
"A_OPUS") {
138 }
else if (part1 ==
"A_REAL") {
140 }
else if (part1 ==
"A_MS" && part2 ==
"ACM") {
142 }
else if (part1 ==
"A_AAC") {
144 if (part2 ==
"MPEG2") {
145 if (part3 ==
"MAIN") {
147 }
else if (part3 ==
"LC") {
149 }
else if (part3 ==
"SBR") {
152 }
else if (part3 ==
"SSR") {
155 }
else if (part2 ==
"MPEG4") {
156 if (part3 ==
"MAIN") {
158 }
else if (part3 ==
"LC") {
160 }
else if (part3 ==
"SBR") {
163 }
else if (part3 ==
"SSR") {
165 }
else if (part3 ==
"LTP") {
169 }
else if (part1 ==
"A_QUICKTIME") {
171 }
else if (part1 ==
"A_TTA1") {
173 }
else if (part1 ==
"A_WAVPACK4") {
175 }
else if (part1 ==
"S_TEXT") {
177 if (part2 ==
"UTF8") {
179 }
else if (part2 ==
"SSA") {
181 }
else if (part2 ==
"ASS") {
183 }
else if (part2 ==
"USF") {
185 }
else if (part2 ==
"WEBVTT") {
188 }
else if (part1 ==
"S_IMAGE") {
190 if (part2 ==
"BMP") {
193 }
else if (part1 ==
"S_VOBSUB") {
195 }
else if (part1 ==
"S_KATE") {
197 }
else if (part1 ==
"B_VOBBTN") {
199 }
else if (part1 ==
"S_DVBSUB") {
201 }
else if (part1 ==
"V_MSWMV") {
209 template <
typename PropertyType,
typename ConversionFunction>
210 void MatroskaTrack::assignPropertyFromTagValue(
const std::unique_ptr<MatroskaTag> &tag,
const char *fieldId, PropertyType &property,
211 const ConversionFunction &conversionFunction,
Diagnostics &diag)
213 const TagValue &value = tag->value(fieldId);
216 property = conversionFunction(value);
217 }
catch (
const ConversionException &) {
221 }
catch (
const ConversionException &) {
222 message = argsToString(
"Ignoring invalid value of \"", fieldId,
'\"',
'.');
224 diag.emplace_back(
DiagLevel::Warning, message, argsToString(
"reading track statatistic from \"", tag->toString(),
'\"'));
229 template <
typename NumberType, Traits::EnableIf<std::is_
integral<NumberType>> * =
nullptr> NumberType tagValueToNumber(
const TagValue &tagValue)
233 switch (tagValue.dataEncoding()) {
236 return bufferToNumber<NumberType>(tagValue.dataPointer(), tagValue.dataSize());
244 template <
typename NumberType, Traits::EnableIf<std::is_
floating_po
int<NumberType>> * =
nullptr>
245 NumberType tagValueToBitrate(
const TagValue &tagValue)
264 using namespace MatroskaTagIds::TrackSpecific;
265 for (
const auto &tag : tags) {
283 static const string context(
"parsing header of Matroska track");
285 m_trackElement->parse(diag);
291 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
292 trackInfoElement = trackInfoElement->nextSibling()) {
294 trackInfoElement->parse(diag);
296 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
299 uint32 defaultDuration = 0;
300 switch (trackInfoElement->id()) {
302 switch (trackInfoElement->readUInteger()) {
323 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
325 subElement->parse(diag);
330 switch (subElement->id()) {
356 m_fps = subElement->readFloat();
369 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
371 subElement->parse(diag);
376 switch (subElement->id()) {
401 m_id = trackInfoElement->readUInteger();
404 m_name = trackInfoElement->readString();
418 m_enabled = trackInfoElement->readUInteger();
421 m_default = trackInfoElement->readUInteger();
424 m_forced = trackInfoElement->readUInteger();
427 m_lacing = trackInfoElement->readUInteger();
430 defaultDuration = trackInfoElement->readUInteger();
436 if (!
m_fps && defaultDuration) {
437 m_fps = 1000000000.0 / defaultDuration;
450 if (codecPrivateElement->
dataSize() >= 0x28) {
460 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
467 if (codecPrivateElement->
dataSize() >= 16) {
473 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
479 auto audioSpecificConfig
482 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
483 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
488 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
490 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
495 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
503 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
565 if (!m_track.name().empty()) {
568 if (!m_track.language().empty()) {
573 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
574 switch (trackInfoElement->id()) {
585 trackInfoElement->makeBuffer();
586 m_dataSize += trackInfoElement->totalSize();
590 m_requiredSize = 1 + m_sizeDenotationLength + m_dataSize;
606 stream.write(buffer, 1 + m_sizeDenotationLength);
614 if (!m_track.
name().empty()) {
622 for (
EbmlElement *trackInfoElement = m_track.m_trackElement->
firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
623 switch (trackInfoElement->id()) {
634 trackInfoElement->copyBuffer(stream);
const std::string & language() const
Returns the language of the track if known; otherwise returns an empty string.
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.
TAG_PARSER_EXPORT const char * numberOfBytes()
ImplementationType * firstChild()
Returns the first child of the element.
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.
TAG_PARSER_EXPORT const char * writingDate()
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
TAG_PARSER_EXPORT const char * bitrate()
The track's bit rate in bits per second.
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.
TAG_PARSER_EXPORT const char * duration()
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)
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.
TAG_PARSER_EXPORT const char * numberOfFrames()
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.
The Diagnostics class is a container for DiagMessage.
uint32 mpeg4SamplingFrequencyTable[13]