Tag Parser 12.4.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
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
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
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()) {
540 }
541 if (!m_displaySize.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
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
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.
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::uint8_t m_extensionChannelConfig
std::uint16_t m_bitsPerSample
bool isEnabled() const
Returns true if the track is marked as enabled; otherwise returns false.
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 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.
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.
Definition margin.h:107
void setLeft(std::uint32_t left)
Sets the left margin to left.
Definition margin.h:75
void setTop(std::uint32_t top)
Sets the top margin to top.
Definition margin.h:59
void setBottom(std::uint32_t bottom)
Sets the bottom margin to bottom.
Definition margin.h:91
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
constexpr std::uint32_t height() const
Returns the height.
Definition size.h:68
void setWidth(std::uint32_t value)
Sets the width.
Definition size.h:76
constexpr std::uint32_t width() const
Returns the width.
Definition size.h:60
void setHeight(std::uint32_t value)
Sets the height.
Definition size.h:84
The TagTarget class specifies the target of a tag.
const IdContainerType & tracks() const
Returns the tracks.
Definition tagtarget.h:105
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...
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 ...
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
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 ...