Improve performance of Matroska writer

Especially when dealing with big files the performance is quite bad. This
change speeds it up a little by using an unordered map to find the elements
for certain offsets instead of using linear lookup.

According to callgrind the modified functions where one with the biggest
own cost. The function updateRelativeOffsets() was actually the 2nd costly
function just below  __memcpy_avx_unaligned_erms.

Now TagParser::EbmlElement::internalParse(TagParser::Diagnostics&) is quite
high as well as standard IO stream functions.
This commit is contained in:
Martchus 2021-01-27 21:24:26 +01:00
parent b39e9dc475
commit fd4c538180
2 changed files with 41 additions and 11 deletions

View File

@ -96,11 +96,13 @@ void MatroskaCuePositionUpdater::parse(EbmlElement *cuesElement, Diagnostics &di
pos = (cueClusterPositionElement = cueTrackPositionsChild)->readUInteger(); pos = (cueClusterPositionElement = cueTrackPositionsChild)->readUInteger();
cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(pos); cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(pos);
m_offsets.emplace(cueTrackPositionsChild, pos); m_offsets.emplace(cueTrackPositionsChild, pos);
m_cueElementByOriginalOffset.emplace(pos, cueTrackPositionsChild);
break; break;
case MatroskaIds::CueCodecState: case MatroskaIds::CueCodecState:
statePos = cueTrackPositionsChild->readUInteger(); statePos = cueTrackPositionsChild->readUInteger();
cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos); cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos);
m_offsets.emplace(cueTrackPositionsChild, statePos); m_offsets.emplace(cueTrackPositionsChild, statePos);
m_cueElementByOriginalOffset.emplace(statePos, cueTrackPositionsChild);
break; break;
case MatroskaIds::CueReference: case MatroskaIds::CueReference:
cueReferenceElementSize = 0; cueReferenceElementSize = 0;
@ -122,6 +124,7 @@ void MatroskaCuePositionUpdater::parse(EbmlElement *cuesElement, Diagnostics &di
statePos = cueReferenceChild->readUInteger(); statePos = cueReferenceChild->readUInteger();
cueReferenceElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos); cueReferenceElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos);
m_offsets.emplace(cueReferenceChild, statePos); m_offsets.emplace(cueReferenceChild, statePos);
m_cueElementByOriginalOffset.emplace(statePos, cueReferenceChild);
break; break;
default: default:
diag.emplace_back(DiagLevel::Warning, diag.emplace_back(DiagLevel::Warning,
@ -143,6 +146,8 @@ void MatroskaCuePositionUpdater::parse(EbmlElement *cuesElement, Diagnostics &di
} else if (cueRelativePositionElement) { } else if (cueRelativePositionElement) {
cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(relPos); cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(relPos);
m_relativeOffsets.emplace(piecewise_construct, forward_as_tuple(cueRelativePositionElement), forward_as_tuple(pos, relPos)); m_relativeOffsets.emplace(piecewise_construct, forward_as_tuple(cueRelativePositionElement), forward_as_tuple(pos, relPos));
m_cueRelativePositionElementByOriginalOffsets.emplace(
piecewise_construct, forward_as_tuple(pos, relPos), forward_as_tuple(cueRelativePositionElement));
} }
cuePointElementSize cuePointElementSize
+= 1 + EbmlElement::calculateSizeDenotationLength(cueTrackPositionsElementSize) + cueTrackPositionsElementSize; += 1 + EbmlElement::calculateSizeDenotationLength(cueTrackPositionsElementSize) + cueTrackPositionsElementSize;
@ -173,12 +178,19 @@ bool MatroskaCuePositionUpdater::updateOffsets(std::uint64_t originalOffset, std
{ {
auto updated = false; auto updated = false;
const auto newOffsetLength = static_cast<int>(EbmlElement::calculateUIntegerLength(newOffset)); const auto newOffsetLength = static_cast<int>(EbmlElement::calculateUIntegerLength(newOffset));
for (auto &offset : m_offsets) { for (auto cueElementRange = m_cueElementByOriginalOffset.equal_range(originalOffset); cueElementRange.first != cueElementRange.second;
if (offset.second.initialValue() == originalOffset && offset.second.currentValue() != newOffset) { ++cueElementRange.first) {
updated = updateSize(offset.first->parent(), newOffsetLength auto *const cueElement = cueElementRange.first->second;
- static_cast<int>(EbmlElement::calculateUIntegerLength(offset.second.currentValue()))) const auto offsetIterator = m_offsets.find(cueElement);
if (offsetIterator == m_offsets.end()) {
continue;
}
auto &offset = offsetIterator->second;
if (offset.currentValue() != newOffset) {
updated
= updateSize(cueElement->parent(), newOffsetLength - static_cast<int>(EbmlElement::calculateUIntegerLength(offset.currentValue())))
|| updated; || updated;
offset.second.update(newOffset); offset.update(newOffset);
} }
} }
return updated; return updated;
@ -193,13 +205,19 @@ bool MatroskaCuePositionUpdater::updateRelativeOffsets(
{ {
auto updated = false; auto updated = false;
const auto newRelativeOffsetLength = static_cast<int>(EbmlElement::calculateUIntegerLength(newRelativeOffset)); const auto newRelativeOffsetLength = static_cast<int>(EbmlElement::calculateUIntegerLength(newRelativeOffset));
for (auto &offset : m_relativeOffsets) { for (auto cueElementRange = m_cueRelativePositionElementByOriginalOffsets.equal_range(std::make_pair(referenceOffset, originalRelativeOffset));
if (offset.second.referenceOffset() == referenceOffset && offset.second.initialValue() == originalRelativeOffset cueElementRange.first != cueElementRange.second; ++cueElementRange.first) {
&& offset.second.currentValue() != newRelativeOffset) { auto *const cueRelativePositionElement = cueElementRange.first->second;
updated = updateSize(offset.first->parent(), newRelativeOffsetLength const auto offsetIterator = m_relativeOffsets.find(cueRelativePositionElement);
- static_cast<int>(EbmlElement::calculateUIntegerLength(offset.second.currentValue()))) if (offsetIterator == m_relativeOffsets.end()) {
continue;
}
auto &offset = offsetIterator->second;
if (offset.currentValue() != newRelativeOffset) {
updated = updateSize(cueRelativePositionElement->parent(),
newRelativeOffsetLength - static_cast<int>(EbmlElement::calculateUIntegerLength(offset.currentValue())))
|| updated; || updated;
offset.second.update(newRelativeOffset); offset.update(newRelativeOffset);
} }
} }
return updated; return updated;

View File

@ -75,11 +75,23 @@ public:
void clear(); void clear();
private: private:
struct PairHash {
template <class T1, class T2> inline std::size_t operator()(const std::pair<T1, T2> &pair) const
{
std::size_t seed = 0;
seed ^= std::hash<T1>()(pair.first) + 0x9e3779b9;
seed ^= std::hash<T2>()(pair.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
bool updateSize(EbmlElement *element, int shift); bool updateSize(EbmlElement *element, int shift);
EbmlElement *m_cuesElement; EbmlElement *m_cuesElement;
std::unordered_map<EbmlElement *, MatroskaOffsetStates> m_offsets; std::unordered_map<EbmlElement *, MatroskaOffsetStates> m_offsets;
std::unordered_multimap<std::uint64_t, EbmlElement *> m_cueElementByOriginalOffset;
std::unordered_map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets; std::unordered_map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets;
std::unordered_multimap<std::pair<std::uint64_t, std::uint64_t>, EbmlElement *, PairHash> m_cueRelativePositionElementByOriginalOffsets;
std::unordered_map<EbmlElement *, std::uint64_t> m_sizes; std::unordered_map<EbmlElement *, std::uint64_t> m_sizes;
}; };