19#include <c++utilities/conversion/stringconversion.h>
38 :
AbstractTrack(trackElement.stream(), trackElement.startOffset())
39 , m_trackElement(&trackElement)
61 auto parts = splitString<vector<string>>(codecId,
"/", EmptyPartsTreat::Keep, 3);
63 const auto &part1 = parts[0], &part2 = parts[1], &part3 = parts[2];
65 if (part1 ==
"V_MS" && part2 ==
"VFW" && part3 ==
"FOURCC") {
67 }
else if (part1 ==
"V_UNCOMPRESSED") {
69 }
else if (part1 ==
"V_MPEG4") {
74 }
else if (part3 ==
"ASP") {
76 }
else if (part3 ==
"AVC") {
79 }
else if (part2 ==
"MS" && part3 ==
"V3") {
82 }
else if (part1 ==
"V_MPEG1") {
84 }
else if (part1 ==
"V_MPEG2") {
86 }
else if (part1 ==
"V_REAL") {
88 }
else if (part1 ==
"V_QUICKTIME") {
90 }
else if (part1 ==
"V_THEORA") {
92 }
else if (part1 ==
"V_PRORES") {
94 }
else if (part1 ==
"V_VP8") {
96 }
else if (part1 ==
"V_VP9") {
98 }
else if (part1 ==
"V_AV1") {
100 }
else if (part1 ==
"A_MPEG") {
104 }
else if (part2 ==
"L2") {
106 }
else if (part2 ==
"L3") {
109 }
else if (part1 ==
"V_MPEGH" && part2 ==
"ISO" && part3 ==
"HEVC") {
111 }
else if (part1 ==
"A_PCM") {
113 if (part2 ==
"INT") {
114 if (part3 ==
"BIG") {
116 }
else if (part3 ==
"LIT") {
119 }
else if (part2 ==
"FLOAT" && part3 ==
"IEEE") {
122 }
else if (part1 ==
"A_MPC") {
124 }
else if (part1 ==
"A_AC3") {
126 }
else if (part1 ==
"A_EAC3") {
128 }
else if (part1 ==
"A_ALAC") {
130 }
else if (part1 ==
"A_DTS") {
132 if (part2 ==
"EXPRESS") {
134 }
else if (part2 ==
"LOSSLESS") {
137 }
else if (part1 ==
"A_VORBIS") {
139 }
else if (part1 ==
"A_FLAC") {
141 }
else if (part1 ==
"A_OPUS") {
143 }
else if (part1 ==
"A_REAL") {
145 }
else if (part1 ==
"A_MS" && part2 ==
"ACM") {
147 }
else if (part1 ==
"A_AAC") {
149 if (part2 ==
"MPEG2") {
150 if (part3 ==
"MAIN") {
152 }
else if (part3 ==
"LC") {
154 }
else if (part3 ==
"SBR") {
157 }
else if (part3 ==
"SSR") {
160 }
else if (part2 ==
"MPEG4") {
161 if (part3 ==
"MAIN") {
163 }
else if (part3 ==
"LC") {
165 }
else if (part3 ==
"SBR") {
168 }
else if (part3 ==
"SSR") {
170 }
else if (part3 ==
"LTP") {
174 }
else if (part1 ==
"A_QUICKTIME") {
176 }
else if (part1 ==
"A_TTA1") {
178 }
else if (part1 ==
"A_WAVPACK4") {
180 }
else if (part1 ==
"S_TEXT") {
182 if (part2 ==
"UTF8") {
184 }
else if (part2 ==
"SSA") {
186 }
else if (part2 ==
"ASS") {
188 }
else if (part2 ==
"USF") {
190 }
else if (part2 ==
"WEBVTT") {
193 }
else if (part1 ==
"S_IMAGE") {
195 if (part2 ==
"BMP") {
198 }
else if (part1 ==
"S_VOBSUB") {
200 }
else if (part1 ==
"S_KATE") {
202 }
else if (part1 ==
"B_VOBBTN") {
204 }
else if (part1 ==
"S_DVBSUB") {
206 }
else if (part1 ==
"V_MSWMV") {
214template <
typename PropertyType,
typename ConversionFunction>
215void MatroskaTrack::assignPropertyFromTagValue(
const std::unique_ptr<MatroskaTag> &tag, std::string_view fieldId, PropertyType &property,
216 const ConversionFunction &conversionFunction,
Diagnostics &diag)
218 const TagValue &value = tag->value(std::string(fieldId));
221 property = conversionFunction(value);
222 }
catch (
const ConversionException &) {
226 }
catch (
const ConversionException &) {
227 message = argsToString(
"Ignoring invalid value of \"", fieldId,
'\"',
'.');
229 diag.emplace_back(
DiagLevel::Warning, message, argsToString(
"reading track statatistic from \"", tag->toString(),
'\"'));
234template <
typename NumberType, Traits::EnableIf<std::is_
integral<NumberType>> * =
nullptr> NumberType tagValueToNumber(
const TagValue &tagValue)
238 switch (tagValue.dataEncoding()) {
241 return bufferToNumber<NumberType>(tagValue.dataPointer(), tagValue.dataSize());
249template <
typename NumberType, Traits::EnableIf<std::is_
floating_po
int<NumberType>> * =
nullptr>
250NumberType tagValueToBitrate(
const TagValue &tagValue)
268 using namespace std::placeholders;
269 using namespace MatroskaTagIds::TrackSpecific;
270 for (
const auto &tag : tags) {
272 if (find(target.
tracks().cbegin(), target.
tracks().cend(),
id()) == target.
tracks().cend()) {
275 assignPropertyFromTagValue(tag, numberOfBytes(),
m_size, &tagValueToNumber<std::uint64_t>, diag);
276 assignPropertyFromTagValue(tag, numberOfFrames(),
m_sampleCount, &tagValueToNumber<std::uint64_t>, diag);
288 CPP_UTILITIES_UNUSED(progress)
290 static const string context(
"parsing header of Matroska track");
292 m_trackElement->
parse(diag);
298 auto hasIsoLanguage =
false;
300 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
301 trackInfoElement = trackInfoElement->
nextSibling()) {
303 trackInfoElement->parse(diag);
305 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
308 std::uint64_t defaultDuration = 0;
309 switch (trackInfoElement->id()) {
311 switch (trackInfoElement->readUInteger()) {
332 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
334 subElement->parse(diag);
339 switch (subElement->id()) {
365 m_fps =
static_cast<std::uint32_t
>(subElement->readFloat());
371 m_colorSpace =
static_cast<std::uint32_t
>(subElement->readUInteger());
378 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
380 subElement->parse(diag);
385 switch (subElement->id()) {
387 m_bitsPerSample =
static_cast<std::uint16_t
>(subElement->readUInteger());
390 m_channelCount =
static_cast<std::uint16_t
>(subElement->readUInteger());
407 m_trackNumber =
static_cast<std::uint32_t
>(trackInfoElement->readUInteger());
410 m_id = trackInfoElement->readUInteger();
413 m_name = trackInfoElement->readString();
417 hasIsoLanguage =
true;
443 defaultDuration = trackInfoElement->readUInteger();
449 if (!
m_fps && defaultDuration) {
450 m_fps =
static_cast<std::uint32_t
>(1000000000.0 /
static_cast<double>(defaultDuration));
463 if (codecPrivateElement->
dataSize() >= 0x28) {
473 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
488 auto audioSpecificConfig
491 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
492 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
497 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
499 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
504 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
512 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
546 if (!hasIsoLanguage) {
568 CPP_UTILITIES_UNUSED(diag);
576 if (!m_track.name().empty()) {
581 const auto languageSize = m_language.empty() ? 3 : m_language.size();
584 const auto languageIETFElementSize
586 m_dataSize += languageElementSize + languageIETFElementSize;
589 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
590 switch (trackInfoElement->id()) {
602 trackInfoElement->makeBuffer();
603 m_dataSize += trackInfoElement->totalSize();
607 m_requiredSize = 1u + m_sizeDenotationLength + m_dataSize;
623 stream.write(buffer, 1 + m_sizeDenotationLength);
631 if (!m_track.
name().empty()) {
635 if (!m_languageIETF.empty()) {
641 switch (trackInfoElement->id()) {
653 trackInfoElement->copyBuffer(stream);
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
std::uint64_t id() const
Returns the track ID if known; otherwise returns 0.
std::uint32_t m_colorSpace
std::uint8_t m_extensionChannelConfig
std::uint64_t m_sampleCount
std::uint16_t m_bitsPerSample
std::uint32_t m_trackNumber
bool isEnabled() const
Returns true if the track is marked as enabled; otherwise returns false.
std::uint16_t m_channelCount
std::uint8_t m_channelConfig
CppUtilities::BinaryReader & reader()
Returns a binary reader for the associated stream.
CppUtilities::TimeSpan m_duration
std::uint32_t trackNumber() const
Returns the track number if known; otherwise returns 0.
CppUtilities::BinaryReader m_reader
CppUtilities::DateTime m_modificationTime
std::uint32_t m_extensionSamplingFrequency
bool isForced() const
Returns true if the track is marked as forced; otherwise returns false.
const std::string name() const
Returns the track name if known; otherwise returns an empty string.
bool isDefault() const
Returns true if the track is marked as default; otherwise returns false.
CppUtilities::DateTime m_creationTime
std::uint32_t m_samplingFrequency
The Diagnostics class is a container for DiagMessage.
The EbmlElement class helps to parse EBML files such as Matroska files.
static void makeSimpleElement(std::ostream &stream, IdentifierType id, std::uint64_t content)
Makes a simple EBML element.
static std::uint8_t calculateSizeDenotationLength(std::uint64_t size)
Returns the length of the size denotation for the specified size in byte.
static std::uint8_t makeSizeDenotation(std::uint64_t size, char *buff)
Makes the size denotation for the specified size and stores it to buff.
static std::uint8_t calculateUIntegerLength(std::uint64_t integer)
Returns the length of the specified unsigned integer in byte.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
ImplementationType * nextSibling()
Returns the next sibling of the element.
ImplementationType * firstChild()
Returns the first child of the element.
DataSizeType dataSize() const
Returns the data size of the element in byte.
void parse(Diagnostics &diag)
Parses the header information of the element which is read from the related stream at the start offse...
std::uint64_t dataOffset() const
Returns the data offset of the element in the related stream.
void setRight(std::uint32_t right)
Sets the right margin to right.
void setLeft(std::uint32_t left)
Sets the left margin to left.
void setTop(std::uint32_t top)
Sets the top margin to top.
void setBottom(std::uint32_t bottom)
Sets the bottom margin to bottom.
Implementation of TagParser::AbstractTrack for the Matroska container.
static MediaFormat codecIdToMediaFormat(const std::string &codecId)
Returns the MediaFormat for the specified Matroska codec ID.
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified.
void readStatisticsFromTags(const std::vector< std::unique_ptr< MatroskaTag > > &tags, Diagnostics &diag)
Reads track-specific statistics from the specified tags.
MatroskaTrack(EbmlElement &trackElement)
Constructs a new track for the specified trackElement.
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override
This method is internally called to parse header information.
~MatroskaTrack() override
Destroys the track.
static void addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track)
Adds the information from the specified avcConfig to the specified track.
static std::unique_ptr< Mpeg4AudioSpecificConfig > parseAudioSpecificConfig(std::istream &stream, std::uint64_t startOffset, std::uint64_t size, Diagnostics &diag)
Parses the audio specific configuration for the track.
constexpr std::uint32_t height() const
Returns the height.
void setWidth(std::uint32_t value)
Sets the width.
constexpr std::uint32_t width() const
Returns the width.
void setHeight(std::uint32_t value)
Sets the height.
The TagTarget class specifies the target of a tag.
const IdContainerType & tracks() const
Returns the tracks.
The TagValue class wraps values of different types.
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation (using th...
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
bool isEmpty() const
Returns whether no or an empty value is assigned.
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
TAG_PARSER_EXPORT MediaFormat fourccToMediaFormat(std::uint32_t fourccId)
@ OutputSamplingFrequency
constexpr TAG_PARSER_EXPORT std::string_view duration()
constexpr TAG_PARSER_EXPORT std::string_view bitrate()
The track's bit rate in bits per second.
TAG_PARSER_EXPORT MediaFormat idToMediaFormat(std::uint8_t mpeg4AudioObjectId, bool sbrPresent=false, bool psPresent=false)
Contains all classes and functions of the TagInfo library.
LocaleFormat
The LocaleFormat enum class specifies the format used by a LocaleDetail.
@ MicrosoftVideoCodecManager
@ MicrosoftAudioCodecManager
@ UncompressedVideoFrames
std::uint32_t mpeg4SamplingFrequencyTable[13]
TrackType
The TrackType enum specifies the underlying file type of a track and the concrete class of the track ...