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)
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") {
214 template <
typename PropertyType,
typename ConversionFunction>
215 void 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(),
'\"'));
234 template <
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());
249 template <
typename NumberType, Traits::EnableIf<std::is_
floating_po
int<NumberType>> * =
nullptr>
250 NumberType 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);
288 CPP_UTILITIES_UNUSED(progress)
290 static const string context(
"parsing header of Matroska track");
292 m_trackElement->parse(diag);
298 auto hasIsoLanguage =
false;
299 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
300 trackInfoElement = trackInfoElement->
nextSibling()) {
302 trackInfoElement->parse(diag);
304 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
307 std::uint64_t defaultDuration = 0;
308 switch (trackInfoElement->id()) {
310 switch (trackInfoElement->readUInteger()) {
331 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
333 subElement->parse(diag);
338 switch (subElement->id()) {
364 m_fps =
static_cast<std::uint32_t
>(subElement->readFloat());
370 m_colorSpace =
static_cast<std::uint32_t
>(subElement->readUInteger());
377 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
379 subElement->parse(diag);
384 switch (subElement->id()) {
386 m_bitsPerSample =
static_cast<std::uint16_t
>(subElement->readUInteger());
389 m_channelCount =
static_cast<std::uint16_t
>(subElement->readUInteger());
406 m_trackNumber =
static_cast<std::uint32_t
>(trackInfoElement->readUInteger());
409 m_id = trackInfoElement->readUInteger();
412 m_name = trackInfoElement->readString();
416 hasIsoLanguage =
true;
442 defaultDuration = trackInfoElement->readUInteger();
448 if (!
m_fps && defaultDuration) {
449 m_fps =
static_cast<std::uint32_t
>(1000000000.0 /
static_cast<double>(defaultDuration));
462 if (codecPrivateElement->
dataSize() >= 0x28) {
472 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
487 auto audioSpecificConfig
490 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
491 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
496 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
498 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
503 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
511 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
545 if (!hasIsoLanguage) {
567 CPP_UTILITIES_UNUSED(diag);
575 if (!m_track.name().empty()) {
580 const auto languageSize = m_language.empty() ? 3 : m_language.size();
583 const auto languageIETFElementSize
585 m_dataSize += languageElementSize + languageIETFElementSize;
588 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
589 switch (trackInfoElement->id()) {
601 trackInfoElement->makeBuffer();
602 m_dataSize += trackInfoElement->totalSize();
606 m_requiredSize = 1u + m_sizeDenotationLength + m_dataSize;
622 stream.write(buffer, 1 + m_sizeDenotationLength);
630 if (!m_track.
name().empty()) {
634 if (!m_languageIETF.empty()) {
640 switch (trackInfoElement->id()) {
652 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
const Locale & locale() const
Returns the locale of the track if known; otherwise returns an empty locale.
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.
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.
void readStatisticsFromTags(const std::vector< std::unique_ptr< MatroskaTag >> &tags, Diagnostics &diag)
Reads track-specific statistics from the specified tags.
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified.
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.
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 writingDate()
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.
constexpr TAG_PARSER_EXPORT std::string_view numberOfBytes()
constexpr TAG_PARSER_EXPORT std::string_view numberOfFrames()
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 ...