5 #include <initializer_list> 20 using namespace MatroskaTagIds;
29 case KnownField::PartNumber:
return partNumber();
30 case KnownField::TotalParts:
return totalParts();
34 case KnownField::Bps:
return bps();
42 case KnownField::Length:
return duration();
43 case KnownField::Language:
return language();
44 default:
return string();
48 KnownField MatroskaTag::knownField(
const std::string &
id)
const 50 using namespace MatroskaTagIds;
51 static const map<string, KnownField> map({
63 {
bps(), KnownField::Bps},
76 }
catch(
const out_of_range &) {
77 return KnownField::Invalid;
91 static const string context(
"parsing Matroska tag");
102 fields().insert(make_pair(field.
id(), field));
105 addNotifications(context, field);
108 parseTargets(*child);
138 void MatroskaTag::make(ostream &stream)
140 prepareMaking().make(stream);
150 void MatroskaTag::parseTargets(
EbmlElement &targetsElement)
152 static const string context(
"parsing targets of Matroska tag");
154 bool targetTypeValueFound =
false;
155 bool targetTypeFound =
false;
156 targetsElement.
parse();
161 addNotification(NotificationType::Critical,
"Unable to parse childs of Targets element.", context);
164 switch(child->id()) {
166 if(!targetTypeValueFound) {
167 m_target.setLevel(child->readUInteger());
168 targetTypeValueFound =
true;
170 addNotification(NotificationType::Warning,
"Targets element contains multiple TargetTypeValue elements. Surplus elements will be ignored.", context);
174 if(!targetTypeFound) {
175 m_target.setLevelName(child->readString());
176 targetTypeFound =
true;
178 addNotification(NotificationType::Warning,
"Targets element contains multiple TargetType elements. Surplus elements will be ignored.", context);
182 m_target.tracks().emplace_back(child->readUInteger());
185 m_target.editions().emplace_back(child->readUInteger());
188 m_target.chapters().emplace_back(child->readUInteger());
191 m_target.attachments().emplace_back(child->readUInteger());
194 addNotification(NotificationType::Warning,
"Targets element contains unknown element. It will be ignored.", context);
197 if(!m_target.level()) {
198 m_target.setLevel(50);
213 MatroskaTagMaker::MatroskaTagMaker(
MatroskaTag &tag) :
218 if(m_tag.target().level() != 50) {
220 m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(m_tag.target().level());
222 if(!m_tag.target().levelName().empty()) {
224 m_targetsSize += 2 + EbmlElement::calculateSizeDenotationLength(m_tag.target().levelName().size()) + m_tag.target().levelName().size();
226 for(
const auto &v : initializer_list<vector<uint64> >{m_tag.target().tracks(), m_tag.target().editions(), m_tag.target().chapters(), m_tag.target().attachments()}) {
229 m_targetsSize += 2 + 1 + EbmlElement::calculateUIntegerLength(uid);
232 m_tagSize = 2 + EbmlElement::calculateSizeDenotationLength(m_targetsSize) + m_targetsSize;
234 m_maker.reserve(m_tag.fields().size());
235 m_simpleTagsSize = 0;
236 for(
auto &pair : m_tag.fields()) {
238 m_maker.emplace_back(pair.second.prepareMaking());
239 m_simpleTagsSize += m_maker.back().requiredSize();
243 m_tag.addNotifications(pair.second);
245 m_tagSize += m_simpleTagsSize;
246 m_totalSize = 2 + EbmlElement::calculateSizeDenotationLength(m_tagSize) + m_tagSize;
256 void MatroskaTagMaker::make(ostream &stream)
const 261 stream.write(buff, 2);
262 byte len = EbmlElement::makeSizeDenotation(m_tagSize, buff);
263 stream.write(buff, len);
266 stream.write(buff, 2);
267 len = EbmlElement::makeSizeDenotation(m_targetsSize, buff);
268 stream.write(buff, len);
270 if(t.
level() != 50) {
273 stream.write(buff, 2);
274 len = EbmlElement::makeUInteger(t.
level(), buff);
275 stream.put(0x80 | len);
276 stream.write(buff, len);
281 stream.write(buff, 2);
282 len = EbmlElement::makeSizeDenotation(t.
levelName().size(), buff);
283 stream.write(buff, len);
287 typedef pair<uint16, vector<uint64> > p;
289 if(!pair.second.empty()) {
290 BE::getBytes(pair.first, buff);
291 for(
auto uid : pair.second) {
292 len = EbmlElement::makeUInteger(uid, buff + 3);
293 *(buff + 2) = 0x80 | len;
294 stream.write(buff, 3 + len);
300 for(
const auto &maker : m_maker) {