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.
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.
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.
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.
TAG_PARSER_EXPORT const char * numberOfFrames()
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.
void readStatisticsFromTags(const std::vector< std::unique_ptr< MatroskaTag >> &tags, Diagnostics &diag)
Reads track-specific statistics from the specified tags.
uint32 m_samplingFrequency
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
TrackType
Specifies the track type.
uint32 mpeg4SamplingFrequencyTable[13]