Tag Parser 12.5.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
matroskatrack.cpp
Go to the documentation of this file.
1#include "./matroskatrack.h"
2#include "./ebmlelement.h"
4#include "./matroskaid.h"
5#include "./matroskatag.h"
6
8
10
12
13#include "../mp4/mp4ids.h"
14#include "../mp4/mp4track.h"
15
16#include "../exceptions.h"
17#include "../mediaformat.h"
18
19#include <c++utilities/conversion/stringconversion.h>
20
21using namespace std;
22using namespace CppUtilities;
23
24namespace TagParser {
25
30
38 : AbstractTrack(trackElement.stream(), trackElement.startOffset())
39 , m_trackElement(&trackElement)
40{
41}
42
49
54
60{
61 auto parts = splitString<vector<string>>(codecId, "/", EmptyPartsTreat::Keep, 3);
62 parts.resize(3);
63 const auto &part1 = parts[0], &part2 = parts[1], &part3 = parts[2];
64 MediaFormat fmt;
65 if (part1 == "V_MS" && part2 == "VFW" && part3 == "FOURCC") {
67 } else if (part1 == "V_UNCOMPRESSED") {
69 } else if (part1 == "V_MPEG4") {
71 if (part2 == "ISO") {
72 if (part3 == "SP") {
74 } else if (part3 == "ASP") {
76 } else if (part3 == "AVC") {
78 }
79 } else if (part2 == "MS" && part3 == "V3") {
81 }
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") {
102 if (part2 == "L1") {
104 } else if (part2 == "L2") {
106 } else if (part2 == "L3") {
108 }
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") {
118 }
119 } else if (part2 == "FLOAT" && part3 == "IEEE") {
121 }
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") {
136 }
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") {
159 }
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") {
172 }
173 }
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") {
192 }
193 } else if (part1 == "S_IMAGE") {
195 if (part2 == "BMP") {
197 }
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") {
208 }
209 return fmt;
210}
211
213
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)
217{
218 const TagValue &value = tag->value(std::string(fieldId));
219 if (!value.isEmpty()) {
220 try {
221 property = conversionFunction(value);
222 } catch (const ConversionException &) {
223 string message;
224 try {
225 message = argsToString("Ignoring invalid value \"", value.toString(TagTextEncoding::Utf8), "\" of \"", fieldId, '\"', '.');
226 } catch (const ConversionException &) {
227 message = argsToString("Ignoring invalid value of \"", fieldId, '\"', '.');
228 }
229 diag.emplace_back(DiagLevel::Warning, message, argsToString("reading track statatistic from \"", tag->toString(), '\"'));
230 }
231 }
232}
233
234template <typename NumberType, Traits::EnableIf<std::is_integral<NumberType>> * = nullptr> NumberType tagValueToNumber(const TagValue &tagValue)
235{
236 // optimization for Latin1/UTF-8 strings
237 if (tagValue.type() == TagDataType::Text) {
238 switch (tagValue.dataEncoding()) {
241 return bufferToNumber<NumberType>(tagValue.dataPointer(), tagValue.dataSize());
242 default:;
243 }
244 }
245 // generic conversion
246 return stringToNumber<NumberType>(tagValue.toString(TagTextEncoding::Utf8));
247}
248
249template <typename NumberType, Traits::EnableIf<std::is_floating_point<NumberType>> * = nullptr>
250NumberType tagValueToBitrate(const TagValue &tagValue)
251{
252 return stringToNumber<NumberType>(tagValue.toString(TagTextEncoding::Utf8)) / 1000;
253}
254
256
266void MatroskaTrack::readStatisticsFromTags(const std::vector<std::unique_ptr<MatroskaTag>> &tags, Diagnostics &diag)
267{
268 using namespace std::placeholders;
269 using namespace MatroskaTagIds::TrackSpecific;
270 for (const auto &tag : tags) {
271 const TagTarget &target = tag->target();
272 if (find(target.tracks().cbegin(), target.tracks().cend(), id()) == target.tracks().cend()) {
273 continue;
274 }
275 assignPropertyFromTagValue(tag, numberOfBytes(), m_size, &tagValueToNumber<std::uint64_t>, diag);
276 assignPropertyFromTagValue(tag, numberOfFrames(), m_sampleCount, &tagValueToNumber<std::uint64_t>, diag);
277 assignPropertyFromTagValue(tag, MatroskaTagIds::TrackSpecific::duration(), m_duration, bind(&TagValue::toTimeSpan, _1), diag);
278 assignPropertyFromTagValue(tag, MatroskaTagIds::TrackSpecific::bitrate(), m_bitrate, &tagValueToBitrate<double>, diag);
279 assignPropertyFromTagValue(tag, writingDate(), m_modificationTime, bind(&TagValue::toDateTime, _1), diag);
280 if (m_creationTime.isNull()) {
282 }
283 }
284}
285
287{
288 CPP_UTILITIES_UNUSED(progress)
289
290 static const string context("parsing header of Matroska track");
291 try {
292 m_trackElement->parse(diag);
293 } catch (const Failure &) {
294 diag.emplace_back(DiagLevel::Critical, "Unable to parse track element.", context);
295 throw;
296 }
297 // read information about the track from the children of the track entry element
298 auto hasIsoLanguage = false;
300 for (EbmlElement *trackInfoElement = m_trackElement->firstChild(), *subElement = nullptr; trackInfoElement;
301 trackInfoElement = trackInfoElement->nextSibling()) {
302 try {
303 trackInfoElement->parse(diag);
304 } catch (const Failure &) {
305 diag.emplace_back(DiagLevel::Critical, "Unable to parse track information element.", context);
306 break;
307 }
308 std::uint64_t defaultDuration = 0;
309 switch (trackInfoElement->id()) {
311 switch (trackInfoElement->readUInteger()) {
314 break;
317 break;
320 break;
323 break;
326 break;
327 default:
329 }
330 break;
332 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
333 try {
334 subElement->parse(diag);
335 } catch (const Failure &) {
336 diag.emplace_back(DiagLevel::Critical, "Unable to parse video track element.", context);
337 break;
338 }
339 switch (subElement->id()) {
341 m_displaySize.setWidth(static_cast<std::uint32_t>(subElement->readUInteger()));
342 break;
344 m_displaySize.setHeight(static_cast<std::uint32_t>(subElement->readUInteger()));
345 break;
347 m_pixelSize.setWidth(static_cast<std::uint32_t>(subElement->readUInteger()));
348 break;
350 m_pixelSize.setHeight(static_cast<std::uint32_t>(subElement->readUInteger()));
351 break;
353 m_cropping.setTop(static_cast<std::uint32_t>(subElement->readUInteger()));
354 break;
356 m_cropping.setLeft(static_cast<std::uint32_t>(subElement->readUInteger()));
357 break;
359 m_cropping.setBottom(static_cast<std::uint32_t>(subElement->readUInteger()));
360 break;
362 m_cropping.setRight(static_cast<std::uint32_t>(subElement->readUInteger()));
363 break;
365 m_fps = static_cast<std::uint32_t>(subElement->readFloat());
366 break;
368 modFlagEnum(m_flags, TrackFlags::Interlaced, subElement->readUInteger());
369 break;
371 m_colorSpace = static_cast<std::uint32_t>(subElement->readUInteger());
372 break;
373 default:;
374 }
375 }
376 break;
378 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
379 try {
380 subElement->parse(diag);
381 } catch (const Failure &) {
382 diag.emplace_back(DiagLevel::Critical, "Unable to parse audio track element.", context);
383 break;
384 }
385 switch (subElement->id()) {
387 m_bitsPerSample = static_cast<std::uint16_t>(subElement->readUInteger());
388 break;
390 m_channelCount = static_cast<std::uint16_t>(subElement->readUInteger());
391 break;
393 if (!m_samplingFrequency) {
394 m_samplingFrequency = static_cast<std::uint32_t>(subElement->readFloat());
395 }
396 break;
399 m_extensionSamplingFrequency = static_cast<std::uint32_t>(subElement->readFloat());
400 }
401 break;
402 default:;
403 }
404 }
405 break;
407 m_trackNumber = static_cast<std::uint32_t>(trackInfoElement->readUInteger());
408 break;
410 m_id = trackInfoElement->readUInteger();
411 break;
413 m_name = trackInfoElement->readString();
414 break;
416 m_locale.emplace_back(trackInfoElement->readString(), LocaleFormat::ISO_639_2_B);
417 hasIsoLanguage = true;
418 break;
420 m_locale.emplace_back(trackInfoElement->readString(), LocaleFormat::BCP_47);
421 break;
423 m_format = codecIdToMediaFormat(m_formatId = trackInfoElement->readString());
424 break;
426 m_formatName = trackInfoElement->readString();
427 break;
429 break; // TODO
431 modFlagEnum(m_flags, TrackFlags::Enabled, trackInfoElement->readUInteger());
432 break;
434 modFlagEnum(m_flags, TrackFlags::Default, trackInfoElement->readUInteger());
435 break;
437 modFlagEnum(m_flags, TrackFlags::Forced, trackInfoElement->readUInteger());
438 break;
440 modFlagEnum(m_flags, TrackFlags::Lacing, trackInfoElement->readUInteger());
441 break;
443 defaultDuration = trackInfoElement->readUInteger();
444 break;
445 default:;
446 }
447 switch (m_mediaType) {
448 case MediaType::Video:
449 if (!m_fps && defaultDuration) {
450 m_fps = static_cast<std::uint32_t>(1000000000.0 / static_cast<double>(defaultDuration));
451 }
452 break;
453 default:;
454 }
455 }
456
457 // read further information from the CodecPrivate element for some codecs
458 EbmlElement *codecPrivateElement;
459 switch (m_format.general) {
461 if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
462 // parse bitmap info header to determine actual format
463 if (codecPrivateElement->dataSize() >= 0x28) {
464 m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
465 BitmapInfoHeader bitmapInfoHeader;
466 bitmapInfoHeader.parse(reader());
467 m_formatId.reserve(m_formatId.size() + 7);
468 m_formatId += " \"";
469 m_formatId += interpretIntegerAsString(bitmapInfoHeader.compression);
470 m_formatId += "\"";
472 } else {
473 diag.emplace_back(DiagLevel::Critical, "BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
474 }
475 }
476 break;
478 if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
479 // parse WAVE header to determine actual format
480 m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
481 WaveFormatHeader waveFormatHeader;
482 waveFormatHeader.parse(reader(), codecPrivateElement->dataSize(), diag);
483 WaveAudioStream::addInfo(waveFormatHeader, *this);
484 }
485 break;
487 if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
488 auto audioSpecificConfig
489 = Mp4Track::parseAudioSpecificConfig(*m_istream, codecPrivateElement->dataOffset(), codecPrivateElement->dataSize(), diag);
491 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
492 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
493 //m_samplingFrequency = audioSpecificConfig->sampleFrequency;
494 } else if (audioSpecificConfig->sampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
495 //m_samplingFrequency = mpeg4SamplingFrequencyTable[audioSpecificConfig->sampleFrequencyIndex];
496 } else {
497 diag.emplace_back(DiagLevel::Warning, "Audio specific config has invalid sample frequency index.", context);
498 }
499 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
500 //m_extensionSamplingFrequency = audioSpecificConfig->extensionSampleFrequency;
501 } else if (audioSpecificConfig->extensionSampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
502 //m_extensionSamplingFrequency = mpeg4SamplingFrequencyTable[audioSpecificConfig->extensionSampleFrequencyIndex];
503 } else {
504 diag.emplace_back(DiagLevel::Warning, "Audio specific config has invalid extension sample frequency index.", context);
505 }
506 m_channelConfig = audioSpecificConfig->channelConfiguration;
507 m_extensionChannelConfig = audioSpecificConfig->extensionChannelConfiguration;
508 }
509 break;
511 if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
512 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
513 try {
514 m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
515 avcConfig->parse(m_reader, codecPrivateElement->dataSize(), diag);
516 Mp4Track::addInfo(*avcConfig, *this);
517 } catch (const TruncatedDataException &) {
518 diag.emplace_back(DiagLevel::Critical, "AVC configuration is truncated.", context);
519 } catch (const Failure &) {
520 diag.emplace_back(DiagLevel::Critical, "AVC configuration is invalid.", context);
521 }
522 }
523 break;
524 default:;
525 }
526
527 // parse format name for unknown formats
528 if (m_format.general == GeneralMediaFormat::Unknown && m_formatName.empty()) {
529 if (startsWith<string>(m_formatId, "V_") || startsWith<string>(m_formatId, "A_") || startsWith<string>(m_formatId, "S_")) {
530 m_formatName = m_formatId.substr(2);
531 } else {
533 }
534 m_formatName.append(" (unknown)");
535 }
536
537 // use pixel size as display size if display size not specified
538 if (!m_displaySize.width()) {
539 m_displaySize.setWidth(m_pixelSize.width());
540 }
541 if (!m_displaySize.height()) {
542 m_displaySize.setHeight(m_pixelSize.height());
543 }
544
545 // set English if no ISO language has been specified (it is the default value of MatroskaIds::TrackLanguage)
546 if (!hasIsoLanguage) {
547 m_locale.emplace_back("eng"sv, LocaleFormat::ISO_639_2_B);
548 }
549}
550
557
562MatroskaTrackHeaderMaker::MatroskaTrackHeaderMaker(const MatroskaTrack &track, Diagnostics &diag)
563 : m_track(track)
564 , m_language(m_track.locale().abbreviatedName(LocaleFormat::ISO_639_2_B, LocaleFormat::Unknown))
565 , m_languageIETF(m_track.locale().abbreviatedName(LocaleFormat::BCP_47))
566 , m_dataSize(0)
567{
568 CPP_UTILITIES_UNUSED(diag);
569
570 // calculate size for recognized elements
571 m_dataSize += 2u + 1u + EbmlElement::calculateUIntegerLength(m_track.id());
572 m_dataSize += 1u + 1u + EbmlElement::calculateUIntegerLength(m_track.trackNumber());
573 m_dataSize += 1u + 1u + EbmlElement::calculateUIntegerLength(m_track.isEnabled());
574 m_dataSize += 1u + 1u + EbmlElement::calculateUIntegerLength(m_track.isDefault());
575 m_dataSize += 2u + 1u + EbmlElement::calculateUIntegerLength(m_track.isForced());
576 if (!m_track.name().empty()) {
577 m_dataSize += 2u + EbmlElement::calculateSizeDenotationLength(m_track.name().size()) + m_track.name().size();
578 }
579
580 // compute size of the mandatory "Language" element (if there's no language set, the 3 byte long value "und" is used)
581 const auto languageSize = m_language.empty() ? 3 : m_language.size();
582 const auto languageElementSize = 3 + EbmlElement::calculateSizeDenotationLength(languageSize) + languageSize;
583 // compute size of the optional "LanguageIETF" element
584 const auto languageIETFElementSize
585 = m_languageIETF.empty() ? 0 : (3 + EbmlElement::calculateSizeDenotationLength(m_languageIETF.size()) + m_languageIETF.size());
586 m_dataSize += languageElementSize + languageIETFElementSize;
587
588 // calculate size for other elements
589 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
590 switch (trackInfoElement->id()) {
599 // skip recognized elements
600 break;
601 default:
602 trackInfoElement->makeBuffer();
603 m_dataSize += trackInfoElement->totalSize();
604 }
605 }
606 m_sizeDenotationLength = EbmlElement::calculateSizeDenotationLength(m_dataSize);
607 m_requiredSize = 1u + m_sizeDenotationLength + m_dataSize;
608}
609
617void MatroskaTrackHeaderMaker::make(ostream &stream) const
618{
619 // make ID and size
620 char buffer[9];
621 *buffer = static_cast<char>(MatroskaIds::TrackEntry);
622 EbmlElement::makeSizeDenotation(m_dataSize, buffer + 1);
623 stream.write(buffer, 1 + m_sizeDenotationLength);
624
625 // make recognized elements
627 EbmlElement::makeSimpleElement(stream, MatroskaIds::TrackNumber, m_track.trackNumber());
631 if (!m_track.name().empty()) {
633 }
634 EbmlElement::makeSimpleElement(stream, MatroskaIds::TrackLanguage, m_language.empty() ? "und" : m_language);
635 if (!m_languageIETF.empty()) {
637 }
638
639 // make other elements
640 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
641 switch (trackInfoElement->id()) {
650 // skip recognized elements
651 break;
652 default:
653 trackInfoElement->copyBuffer(stream);
654 }
655 }
656}
657
658} // namespace TagParser
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
std::uint8_t m_extensionChannelConfig
std::uint64_t startOffset() const
Returns the start offset of the track in the associated stream.
std::uint16_t m_bitsPerSample
AbstractTrack(std::istream &inputStream, std::ostream &outputStream, std::uint64_t startOffset)
Constructs a new track.
CppUtilities::BinaryReader & reader()
Returns a binary reader for the associated stream.
CppUtilities::TimeSpan m_duration
CppUtilities::BinaryReader m_reader
CppUtilities::DateTime m_modificationTime
std::uint32_t m_extensionSamplingFrequency
CppUtilities::DateTime m_creationTime
std::uint32_t m_samplingFrequency
The BitmapInfoHeader class parses the BITMAPINFOHEADER structure defined by MS.
void parse(CppUtilities::BinaryReader &reader)
Parses the BITMAPINFOHEADER structure using the specified reader.
The Diagnostics class is a container for DiagMessage.
The EbmlElement class helps to parse EBML files such as Matroska files.
Definition ebmlelement.h:32
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...
Definition exceptions.h:11
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 make(std::ostream &stream) const
Saves the header for the track (specified when constructing the object) to the specified stream (make...
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.
The MediaFormat class specifies the format of media data.
unsigned char extension
GeneralMediaFormat general
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.
Definition mp4track.cpp:706
The TagTarget class specifies the target of a tag.
Definition tagtarget.h:20
const IdContainerType & tracks() const
Returns the tracks.
Definition tagtarget.h:105
The TagValue class wraps values of different types.
Definition tagvalue.h:147
CppUtilities::DateTime toDateTime() const
Converts the value of the current TagValue object to its equivalent DateTime representation (using th...
Definition tagvalue.cpp:763
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
Definition tagvalue.h:450
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition tagvalue.h:490
CppUtilities::TimeSpan toTimeSpan() const
Converts the value of the current TagValue object to its equivalent TimeSpan representation.
Definition tagvalue.cpp:724
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition exceptions.h:39
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
The WaveFormatHeader class parses the WAVEFORMATEX structure defined by MS.
std::uint64_t parse(CppUtilities::BinaryReader &reader, std::uint64_t maxSize, Diagnostics &diag)
Parses the WAVE "fmt " header segment using the specified reader.
TAG_PARSER_EXPORT MediaFormat fourccToMediaFormat(std::uint32_t fourccId)
Definition mp4ids.cpp:51
Encapsulates track-specific Matroska tag IDs written by mkvmerge 7.0.0 or newer.
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)
Definition mp4ids.cpp:373
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
LocaleFormat
The LocaleFormat enum class specifies the format used by a LocaleDetail.
std::uint32_t mpeg4SamplingFrequencyTable[13]
Definition mp4ids.cpp:429
TrackType
The TrackType enum specifies the underlying file type of a track and the concrete class of the track ...