Skip to content

Commit b8a5905

Browse files
Tolriqufleisch
authored andcommitted
Matroska: Use seek head for faster element lookup (#1321)
1 parent 13751f5 commit b8a5905

6 files changed

Lines changed: 78 additions & 13 deletions

File tree

examples/tagreader.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,3 @@ int main(int argc, char *argv[])
117117
}
118118
return 0;
119119
}
120-

taglib/fileref.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ namespace
225225
#endif
226226
#ifdef TAGLIB_WITH_MATROSKA
227227
else if(ext == "MKA" || ext == "MKV" || ext == "WEBM")
228-
file = new Matroska::File(stream, readAudioProperties);
228+
file = new Matroska::File(stream, readAudioProperties, audioPropertiesStyle);
229229
#endif
230230

231231
// if file is not valid, leave it to content-based detection.

taglib/matroska/ebml/ebmlmksegment.cpp

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,32 @@
3030

3131
using namespace TagLib;
3232

33+
namespace {
34+
35+
template <EBML::Element::Id Id, typename ElementType>
36+
std::unique_ptr<ElementType> readElementAt(File &file,
37+
offset_t offset,
38+
offset_t maxOffset)
39+
{
40+
if(offset < 0 || offset >= maxOffset) {
41+
return nullptr;
42+
}
43+
44+
file.seek(offset);
45+
auto element = EBML::Element::factory(file);
46+
if(!element || element->getId() != Id) {
47+
return nullptr;
48+
}
49+
50+
auto typed = EBML::element_cast<Id>(std::move(element));
51+
if(!typed || !typed->read(file)) {
52+
return nullptr;
53+
}
54+
return typed;
55+
}
56+
57+
} // namespace
58+
3359
EBML::MkSegment::MkSegment(int sizeLength, offset_t dataSize, offset_t offset):
3460
MasterElement(Id::MkSegment, sizeLength, dataSize, offset)
3561
{
@@ -51,14 +77,55 @@ bool EBML::MkSegment::read(File &file)
5177
{
5278
const offset_t maxOffset = file.tell() + dataSize;
5379
std::unique_ptr<Element> element;
54-
int i = 0;
55-
int seekHeadIndex = -1;
5680
while((element = findNextElement(file, maxOffset))) {
5781
if(const Id id = element->getId(); id == Id::MkSeekHead) {
58-
seekHeadIndex = i;
5982
seekHead = element_cast<Id::MkSeekHead>(std::move(element));
6083
if(!seekHead->read(file))
6184
return false;
85+
// We have a seek head, let's use it for faster access to the other elements
86+
if(const auto elementAfterSeekHead = findNextElement(file, maxOffset);
87+
elementAfterSeekHead && elementAfterSeekHead->getId() == Id::VoidElement)
88+
seekHead->setPadding(elementAfterSeekHead->getSize());
89+
const offset_t segDataOffset = segmentDataOffset();
90+
const auto matroskaSeekHead = parseSeekHead();
91+
for(const auto &[idValue, relativeOffset] : matroskaSeekHead->entryList()) {
92+
const offset_t absoluteOffset = segDataOffset + relativeOffset;
93+
switch(static_cast<Id>(idValue)) {
94+
case Id::MkCues:
95+
if(!((cues = readElementAt<Id::MkCues, MkCues>(
96+
file, absoluteOffset, maxOffset))))
97+
return false;
98+
break;
99+
case Id::MkInfo:
100+
if(!((info = readElementAt<Id::MkInfo, MkInfo>(
101+
file, absoluteOffset, maxOffset))))
102+
return false;
103+
break;
104+
case Id::MkTracks:
105+
if(!((tracks = readElementAt<Id::MkTracks, MkTracks>(
106+
file, absoluteOffset, maxOffset))))
107+
return false;
108+
break;
109+
case Id::MkTags:
110+
if(!((tags = readElementAt<Id::MkTags, MkTags>(
111+
file, absoluteOffset, maxOffset))))
112+
return false;
113+
break;
114+
case Id::MkAttachments:
115+
if(!((attachments = readElementAt<Id::MkAttachments, MkAttachments>(
116+
file, absoluteOffset, maxOffset))))
117+
return false;
118+
break;
119+
case Id::MkChapters:
120+
if(!((chapters = readElementAt<Id::MkChapters, MkChapters>(
121+
file, absoluteOffset, maxOffset))))
122+
return false;
123+
break;
124+
default:
125+
break;
126+
}
127+
}
128+
return true;
62129
}
63130
else if(id == Id::MkCues) {
64131
cues = element_cast<Id::MkCues>(std::move(element));
@@ -91,14 +158,8 @@ bool EBML::MkSegment::read(File &file)
91158
return false;
92159
}
93160
else {
94-
if(id == Id::VoidElement
95-
&& seekHead
96-
&& seekHeadIndex == i - 1)
97-
seekHead->setPadding(element->getSize());
98-
99161
element->skipData(file);
100162
}
101-
i++;
102163
}
103164
return true;
104165
}

taglib/matroska/matroskafile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,14 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle)
389389
}
390390

391391
// Read the segment into memory from file
392+
d->segment = segment->parseSegment();
392393
if(!segment->read(*this)) {
393394
debug("Failed to read segment");
394395
setValid(false);
395396
return;
396397
}
397398

398399
// Parse the elements
399-
d->segment = segment->parseSegment();
400400
d->seekHead = segment->parseSeekHead();
401401
d->cues = segment->parseCues();
402402
d->tag = segment->parseTag();

taglib/matroska/matroskaseekhead.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ bool Matroska::SeekHead::isValid(TagLib::File &file) const
5454
void Matroska::SeekHead::addEntry(const Element &element)
5555
{
5656
entries.append({element.id(), element.offset()});
57-
debug("adding to seekhead");
5857
setNeedsRender(true);
5958
}
6059

@@ -64,6 +63,11 @@ void Matroska::SeekHead::addEntry(ID id, offset_t offset)
6463
setNeedsRender(true);
6564
}
6665

66+
const List<std::pair<unsigned int, offset_t>> &Matroska::SeekHead::entryList() const
67+
{
68+
return entries;
69+
}
70+
6771
ByteVector Matroska::SeekHead::renderInternal()
6872
{
6973
const auto beforeSize = sizeRenderedOrWritten();

taglib/matroska/matroskaseekhead.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace TagLib {
3939
bool isValid(TagLib::File &file) const;
4040
void addEntry(const Element &element);
4141
void addEntry(ID id, offset_t offset);
42+
const List<std::pair<unsigned int, offset_t>> &entryList() const;
4243
void write(TagLib::File &file) override;
4344
void sort();
4445
bool sizeChanged(Element &caller, offset_t delta) override;

0 commit comments

Comments
 (0)