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,
const char *fieldId, PropertyType &property,
216 const ConversionFunction &conversionFunction,
Diagnostics &diag)
218 const TagValue &value = tag->value(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 static const string context(
"parsing header of Matroska track");
290 m_trackElement->parse(diag);
296 for (
EbmlElement *trackInfoElement = m_trackElement->
firstChild(), *subElement =
nullptr; trackInfoElement;
297 trackInfoElement = trackInfoElement->nextSibling()) {
299 trackInfoElement->parse(diag);
301 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse track information element.", context);
304 std::uint32_t defaultDuration = 0;
305 switch (trackInfoElement->id()) {
307 switch (trackInfoElement->readUInteger()) {
328 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
330 subElement->parse(diag);
335 switch (subElement->id()) {
361 m_fps = subElement->readFloat();
374 for (subElement = trackInfoElement->firstChild(); subElement; subElement = subElement->nextSibling()) {
376 subElement->parse(diag);
381 switch (subElement->id()) {
406 m_id = trackInfoElement->readUInteger();
409 m_name = trackInfoElement->readString();
423 m_enabled = trackInfoElement->readUInteger();
426 m_default = trackInfoElement->readUInteger();
429 m_forced = trackInfoElement->readUInteger();
432 m_lacing = trackInfoElement->readUInteger();
435 defaultDuration = trackInfoElement->readUInteger();
441 if (!
m_fps && defaultDuration) {
442 m_fps = 1000000000.0 / defaultDuration;
455 if (codecPrivateElement->
dataSize() >= 0x28) {
465 diag.emplace_back(
DiagLevel::Critical,
"BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context);
480 auto audioSpecificConfig
483 audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
484 if (audioSpecificConfig->sampleFrequencyIndex == 0xF) {
489 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid sample frequency index.", context);
491 if (audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
496 diag.emplace_back(
DiagLevel::Warning,
"Audio specific config has invalid extension sample frequency index.", context);
504 auto avcConfig = make_unique<TagParser::AvcConfiguration>();
558 CPP_UTILITIES_UNUSED(diag);
566 if (!m_track.name().empty()) {
569 if (!m_track.language().empty()) {
574 for (EbmlElement *trackInfoElement = m_track.m_trackElement->firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
575 switch (trackInfoElement->id()) {
586 trackInfoElement->makeBuffer();
587 m_dataSize += trackInfoElement->totalSize();
591 m_requiredSize = 1 + m_sizeDenotationLength + m_dataSize;
607 stream.write(buffer, 1 + m_sizeDenotationLength);
615 if (!m_track.
name().empty()) {
623 for (
EbmlElement *trackInfoElement = m_track.m_trackElement->
firstChild(); trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) {
624 switch (trackInfoElement->id()) {
635 trackInfoElement->copyBuffer(stream);