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 ==
"V_AV1") {
99 }
else if (part1 ==
"A_MPEG") {
103 }
else if (part2 ==
"L2") {
105 }
else if (part2 ==
"L3") {
108 }
else if (part1 ==
"V_MPEGH" && part2 ==
"ISO" && part3 ==
"HEVC") {
110 }
else if (part1 ==
"A_PCM") {
112 if (part2 ==
"INT") {
113 if (part3 ==
"BIG") {
115 }
else if (part3 ==
"LIT") {
118 }
else if (part2 ==
"FLOAT" && part3 ==
"IEEE") {
121 }
else if (part1 ==
"A_MPC") {
123 }
else if (part1 ==
"A_AC3") {
125 }
else if (part1 ==
"A_ALAC") {
127 }
else if (part1 ==
"A_DTS") {
129 if (part2 ==
"EXPRESS") {
131 }
else if (part2 ==
"LOSSLESS") {
134 }
else if (part1 ==
"A_VORBIS") {
136 }
else if (part1 ==
"A_FLAC") {
138 }
else if (part1 ==
"A_OPUS") {
140 }
else if (part1 ==
"A_REAL") {
142 }
else if (part1 ==
"A_MS" && part2 ==
"ACM") {
144 }
else if (part1 ==
"A_AAC") {
146 if (part2 ==
"MPEG2") {
147 if (part3 ==
"MAIN") {
149 }
else if (part3 ==
"LC") {
151 }
else if (part3 ==
"SBR") {
154 }
else if (part3 ==
"SSR") {
157 }
else if (part2 ==
"MPEG4") {
158 if (part3 ==
"MAIN") {
160 }
else if (part3 ==
"LC") {
162 }
else if (part3 ==
"SBR") {
165 }
else if (part3 ==
"SSR") {
167 }
else if (part3 ==
"LTP") {
171 }
else if (part1 ==
"A_QUICKTIME") {
173 }
else if (part1 ==
"A_TTA1") {
175 }
else if (part1 ==
"A_WAVPACK4") {
177 }
else if (part1 ==
"S_TEXT") {
179 if (part2 ==
"UTF8") {
181 }
else if (part2 ==
"SSA") {
183 }
else if (part2 ==
"ASS") {
185 }
else if (part2 ==
"USF") {
187 }
else if (part2 ==
"WEBVTT") {
190 }
else if (part1 ==
"S_IMAGE") {
192 if (part2 ==
"BMP") {
195 }
else if (part1 ==
"S_VOBSUB") {
197 }
else if (part1 ==
"S_KATE") {
199 }
else if (part1 ==
"B_VOBBTN") {
201 }
else if (part1 ==
"S_DVBSUB") {
203 }
else if (part1 ==
"V_MSWMV") {
211 template <
typename PropertyType,
typename ConversionFunction>
212 void MatroskaTrack::assignPropertyFromTagValue(
const std::unique_ptr<MatroskaTag> &tag,
const char *fieldId, PropertyType &property,
213 const ConversionFunction &conversionFunction,
Diagnostics &diag)
215 const TagValue &value = tag->value(fieldId);
218 property = conversionFunction(value);
219 }
catch (
const ConversionException &) {
223 }
catch (
const ConversionException &) {
224 message = argsToString(
"Ignoring invalid value of \"", fieldId,
'\"',
'.');
226 diag.emplace_back(
DiagLevel::Warning, message, argsToString(
"reading track statatistic from \"", tag->toString(),
'\"'));
231 template <
typename NumberType, Traits::EnableIf<std::is_
integral<NumberType>> * =
nullptr> NumberType tagValueToNumber(
const TagValue &tagValue)
235 switch (tagValue.dataEncoding()) {
238 return bufferToNumber<NumberType>(tagValue.dataPointer(), tagValue.dataSize());
246 template <
typename NumberType, Traits::EnableIf<std::is_
floating_po
int<NumberType>> * =
nullptr>
247 NumberType tagValueToBitrate(
const TagValue &tagValue)
265 using namespace std::placeholders;
266 using namespace MatroskaTagIds::TrackSpecific;
267 for (
const auto &tag : tags) {
272 assignPropertyFromTagValue(tag,
numberOfBytes(),
m_size, &tagValueToNumber<std::uint64_t>, diag);
285 static const string context(
"parsing header of Matroska track");
287 m_trackElement->parse(diag);
293 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
294 trackInfoElement = trackInfoElement->nextSibling()) {
296 trackInfoElement->parse(diag);
298 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
301 std::uint32_t defaultDuration = 0;
302 switch (trackInfoElement->id()) {
304 switch (trackInfoElement->readUInteger()) {
325 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
327 subElement->parse(diag);
332 switch (subElement->id()) {
358 m_fps = subElement->readFloat();
371 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
373 subElement->parse(diag);
378 switch (subElement->id()) {
403 m_id = trackInfoElement->readUInteger();
406 m_name = trackInfoElement->readString();
420 m_enabled = trackInfoElement->readUInteger();
423 m_default = trackInfoElement->readUInteger();
426 m_forced = trackInfoElement->readUInteger();
429 m_lacing = trackInfoElement->readUInteger();
432 defaultDuration = trackInfoElement->readUInteger();
438 if (!
m_fps && defaultDuration) {
439 m_fps = 1000000000.0 / defaultDuration;
452 if (codecPrivateElement->
dataSize() >= 0x28) {
462 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
477 auto audioSpecificConfig
480 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
481 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
486 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
488 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
493 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
501 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
555 CPP_UTILITIES_UNUSED(diag);
563 if (!m_track.name().empty()) {
566 if (!m_track.language().empty()) {
571 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
572 switch (trackInfoElement->id()) {
583 trackInfoElement->makeBuffer();
584 m_dataSize += trackInfoElement->totalSize();
588 m_requiredSize = 1 + m_sizeDenotationLength + m_dataSize;
604 stream.write(buffer, 1 + m_sizeDenotationLength);
612 if (!m_track.
name().empty()) {
620 for (
EbmlElement *trackInfoElement = m_track.m_trackElement->
firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
621 switch (trackInfoElement->id()) {
632 trackInfoElement->copyBuffer(stream);