Coverage Report

Created: 2026-08-13 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mkv/matroska_segment_seeker.cpp
Line
Count
Source
1
/*****************************************************************************
2
 * matroska_segment.hpp : matroska demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2016 VLC authors and VideoLAN
5
 *
6
 * Authors: Filip Roséen <filip@videolabs.io>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
#include "matroska_segment_seeker.hpp"
24
#include "matroska_segment.hpp"
25
#include "demux.hpp"
26
#include "Ebml_parser.hpp"
27
#include "Ebml_dispatcher.hpp"
28
#include "util.hpp"
29
#include "stream_io_callback.hpp"
30
31
#include <sstream>
32
#include <limits>
33
34
namespace {
35
    template<class It, class T>
36
    It greatest_lower_bound( It beg, It end, T const& value )
37
11.9k
    {
38
11.9k
        It it = std::upper_bound( beg, end, value );
39
11.9k
        if( it != beg ) --it;
40
11.9k
        return it;
41
11.9k
    }
matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, mkv::SegmentSeeker::Seekpoint>(std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>, mkv::SegmentSeeker::Seekpoint const&)
Line
Count
Source
37
5.88k
    {
38
5.88k
        It it = std::upper_bound( beg, end, value );
39
5.88k
        if( it != beg ) --it;
40
5.88k
        return it;
41
5.88k
    }
matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, mkv::SegmentSeeker::Range>(std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, std::__1::__wrap_iter<mkv::SegmentSeeker::Range const*>, mkv::SegmentSeeker::Range const&)
Line
Count
Source
37
2.11k
    {
38
2.11k
        It it = std::upper_bound( beg, end, value );
39
2.11k
        if( it != beg ) --it;
40
2.11k
        return it;
41
2.11k
    }
matroska_segment_seeker.cpp:std::__1::__wrap_iter<unsigned long*> (anonymous namespace)::greatest_lower_bound<std::__1::__wrap_iter<unsigned long*>, unsigned long>(std::__1::__wrap_iter<unsigned long*>, std::__1::__wrap_iter<unsigned long*>, unsigned long const&)
Line
Count
Source
37
3.91k
    {
38
3.91k
        It it = std::upper_bound( beg, end, value );
39
3.91k
        if( it != beg ) --it;
40
3.91k
        return it;
41
3.91k
    }
42
43
    // std::prev and std::next exists in C++11, in order to avoid ambiguity due
44
    // to ADL and iterators being defined within namespace std, these two
45
    // function-names have been postfixed with an underscore.
46
47
28.4k
    template<class It> It prev_( It it ) { return --it; }
48
76.0k
    template<class It> It next_( It it ) { return ++it; }
matroska_segment_seeker.cpp:std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> > (anonymous namespace)::next_<std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> > >(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, std::__1::__tree_node<std::__1::__value_type<long, mkv::SegmentSeeker::Cluster>, void*>*, long> >)
Line
Count
Source
48
73.9k
    template<class It> It next_( It it ) { return ++it; }
matroska_segment_seeker.cpp:std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> (anonymous namespace)::next_<std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*> >(std::__1::__wrap_iter<mkv::SegmentSeeker::Seekpoint const*>)
Line
Count
Source
48
2.15k
    template<class It> It next_( It it ) { return ++it; }
49
}
50
51
namespace mkv {
52
53
SegmentSeeker::cluster_positions_t::iterator
54
SegmentSeeker::add_cluster_position( fptr_t fpos )
55
58.9k
{
56
58.9k
    cluster_positions_t::iterator insertion_point = std::upper_bound(
57
58.9k
      _cluster_positions.begin(),
58
58.9k
      _cluster_positions.end(),
59
58.9k
      fpos
60
58.9k
    );
61
62
58.9k
    return _cluster_positions.insert( insertion_point, fpos );
63
58.9k
}
64
65
SegmentSeeker::cluster_map_t::iterator
66
SegmentSeeker::add_cluster( KaxCluster * const p_cluster )
67
49.4k
{
68
49.4k
    Cluster cinfo = {
69
49.4k
        /* fpos     */ p_cluster->GetElementPosition(),
70
49.4k
        /* pts      */ vlc_tick_t( VLC_TICK_FROM_NS( p_cluster->GlobalTimestamp() ) ),
71
49.4k
        /* duration */ vlc_tick_t( -1 ),
72
49.4k
        /* size     */ p_cluster->IsFiniteSize()
73
49.4k
            ? p_cluster->GetEndPosition() - p_cluster->GetElementPosition()
74
49.4k
            : UINT64_MAX
75
49.4k
    };
76
77
49.4k
    add_cluster_position( cinfo.fpos );
78
79
49.4k
    cluster_map_t::iterator it = _clusters.lower_bound( cinfo.pts );
80
81
49.4k
    if( it != _clusters.end() && it->second.pts == cinfo.pts )
82
45.3k
    {
83
        // cluster already known
84
45.3k
    }
85
4.11k
    else
86
4.11k
    {
87
4.11k
        it = _clusters.insert( cluster_map_t::value_type( cinfo.pts, cinfo ) ).first;
88
4.11k
    }
89
90
    // ------------------------------------------------------------------
91
    // IF we have two adjecent clusters, update duration where applicable
92
    // ------------------------------------------------------------------
93
94
49.4k
    struct Duration {
95
49.4k
        static void fix( Cluster& prev, Cluster& next )
96
52.8k
        {
97
52.8k
            if( ( prev.fpos + prev.size) == next.fpos )
98
1.49k
                prev.duration = next.pts - prev.pts;
99
52.8k
        }
100
49.4k
    };
101
102
49.4k
    if( it != _clusters.begin() )
103
28.4k
    {
104
28.4k
        Duration::fix( prev_( it )->second, it->second );
105
28.4k
    }
106
107
49.4k
    if( it != _clusters.end() && next_( it ) != _clusters.end() )
108
24.4k
    {
109
24.4k
        Duration::fix( it->second, next_( it )->second );
110
24.4k
    }
111
112
49.4k
    return it;
113
49.4k
}
114
115
void
116
SegmentSeeker::add_seekpoint( track_id_t track_id, Seekpoint sp )
117
28.1k
{
118
28.1k
    seekpoints_t&  seekpoints = _tracks_seekpoints[ track_id ];
119
28.1k
    seekpoints_t::iterator it = std::lower_bound( seekpoints.begin(), seekpoints.end(), sp );
120
121
28.1k
    if( it != seekpoints.end() && it->fpos == sp.fpos )
122
865
    {
123
865
        if (sp.trust_level <= it->trust_level)
124
863
            return;
125
126
2
        *it = sp;
127
2
    }
128
27.2k
    else if( it != seekpoints.end() && it->pts == sp.pts )
129
18.1k
    {
130
18.1k
        if (sp.trust_level <= it->trust_level)
131
17.9k
            return;
132
133
215
        *it = sp;
134
215
    }
135
9.16k
    else
136
9.16k
    {
137
9.16k
        seekpoints.insert( it, sp );
138
9.16k
    }
139
28.1k
}
140
141
SegmentSeeker::tracks_seekpoint_t
142
SegmentSeeker::find_greatest_seekpoints_in_range( fptr_t start_fpos, vlc_tick_t end_pts, track_ids_t const& filter_tracks )
143
2.13k
{
144
2.13k
    tracks_seekpoint_t tpoints;
145
146
5.90k
    for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it )
147
3.76k
    {
148
3.76k
        if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() )
149
42
            continue;
150
151
3.72k
        Seekpoint sp = get_first_seekpoint_around( end_pts, it->second );
152
153
3.72k
        if( sp.fpos < start_fpos )
154
13
            continue;
155
156
3.71k
        if( sp.pts > end_pts )
157
0
            continue;
158
159
3.71k
        tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) );
160
3.71k
    }
161
162
2.13k
    if (tpoints.empty())
163
7
    {
164
        // try a further pts
165
14
        for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it )
166
7
        {
167
7
            if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() )
168
0
                continue;
169
170
7
            Seekpoint sp = get_first_seekpoint_around( end_pts, it->second );
171
172
7
            if( sp.fpos < start_fpos )
173
7
                continue;
174
175
0
            tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) );
176
0
        }
177
7
    }
178
179
2.13k
    return tpoints;
180
2.13k
}
181
182
SegmentSeeker::Seekpoint
183
SegmentSeeker::get_first_seekpoint_around( vlc_tick_t pts, seekpoints_t const& seekpoints,
184
                                           Seekpoint::TrustLevel trust_level )
185
3.73k
{
186
3.73k
    if( seekpoints.empty() )
187
0
    {
188
0
        return Seekpoint();
189
0
    }
190
191
3.73k
    typedef seekpoints_t::const_iterator iterator;
192
193
3.73k
    Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts );
194
195
3.73k
    iterator const it_begin  = seekpoints.begin();
196
3.73k
    iterator const it_end    = seekpoints.end();
197
3.73k
    iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle );
198
199
3.73k
    iterator it_before;
200
201
    // rewrind to _previous_ seekpoint with appropriate trust
202
3.75k
    for( it_before = it_middle; it_before != it_begin; --it_before )
203
1.22k
    {
204
1.22k
        if( it_before->trust_level >= trust_level )
205
1.19k
            return *it_before;
206
1.22k
    }
207
2.53k
    return *it_begin;
208
3.73k
}
209
210
SegmentSeeker::seekpoint_pair_t
211
SegmentSeeker::get_seekpoints_around( vlc_tick_t pts, seekpoints_t const& seekpoints )
212
2.15k
{
213
2.15k
    if( seekpoints.empty() )
214
0
    {
215
0
        return seekpoint_pair_t();
216
0
    }
217
218
2.15k
    typedef seekpoints_t::const_iterator iterator;
219
220
2.15k
    Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts );
221
222
2.15k
    iterator const it_begin  = seekpoints.begin();
223
2.15k
    iterator const it_end    = seekpoints.end();
224
2.15k
    iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle );
225
226
2.15k
    if ( it_middle != it_end && (*it_middle).pts > pts)
227
        // found nothing low enough, use the first one
228
0
        return seekpoint_pair_t( *it_begin, Seekpoint() );
229
230
2.15k
    iterator it_before = it_middle;
231
2.15k
    iterator it_after = it_middle == it_end ? it_middle : next_( it_middle ) ;
232
233
2.15k
    return seekpoint_pair_t( *it_before,
234
2.15k
      it_after == it_end ? Seekpoint() : *it_after
235
2.15k
    );
236
2.15k
}
237
238
SegmentSeeker::seekpoint_pair_t
239
SegmentSeeker::get_seekpoints_around( vlc_tick_t target_pts, track_ids_t const& priority_tracks )
240
2.14k
{
241
2.14k
    seekpoint_pair_t points;
242
243
2.14k
    if( _tracks_seekpoints.empty() )
244
14
        return points;
245
246
2.13k
    { // locate the max/min seekpoints for priority_tracks //
247
248
2.13k
        typedef track_ids_t::const_iterator track_iterator;
249
250
2.13k
        track_iterator const begin = priority_tracks.begin();
251
2.13k
        track_iterator const end   = priority_tracks.end();
252
253
4.28k
        for( track_iterator it = begin; it != end; ++it )
254
2.15k
        {
255
2.15k
            seekpoint_pair_t track_points = get_seekpoints_around( target_pts, _tracks_seekpoints[ *it ] );
256
257
2.15k
            if( it == begin ) {
258
2.13k
                points = track_points;
259
2.13k
                continue;
260
2.13k
            }
261
262
21
            if( track_points.first.trust_level > Seekpoint::DISABLED &&
263
21
                points.first.fpos > track_points.first.fpos )
264
0
                points.first = track_points.first;
265
266
21
            if( track_points.second.trust_level > Seekpoint::DISABLED &&
267
0
                points.second.fpos < track_points.second.fpos )
268
0
                points.second = track_points.second;
269
21
        }
270
2.13k
    }
271
272
2.13k
    { // check if we got a cluster which is closer to target_pts than the found cues //
273
274
2.13k
        cluster_map_t::iterator it = _clusters.lower_bound( target_pts );
275
276
2.13k
        if( it != _clusters.begin() && --it != _clusters.end() )
277
33
        {
278
33
            Cluster const& cluster = it->second;
279
280
33
            if( cluster.fpos > points.first.fpos )
281
11
            {
282
11
                points.first = Seekpoint( cluster.fpos, cluster.pts );
283
284
                // do we need to update the max point? //
285
286
11
                if( points.second.fpos < points.first.fpos )
287
0
                    points.second = Seekpoint( cluster.fpos + cluster.size, cluster.pts + cluster.duration );
288
11
            }
289
33
        }
290
2.13k
    }
291
292
2.13k
    return points;
293
2.14k
}
294
295
SegmentSeeker::tracks_seekpoint_t
296
SegmentSeeker::get_seekpoints( matroska_segment_c& ms, vlc_tick_t target_pts,
297
                               track_ids_t const& priority_tracks, track_ids_t const& filter_tracks )
298
2.14k
{
299
2.14k
    struct contains_all_of_t {
300
2.14k
        bool operator()( tracks_seekpoint_t const& haystack, track_ids_t const& track_ids )
301
2.14k
        {
302
4.28k
            for( track_ids_t::const_iterator it = track_ids.begin(); it != track_ids.end(); ++it ) {
303
2.15k
                if( haystack.find( *it ) == haystack.end() )
304
8
                    return false;
305
2.15k
            }
306
307
2.12k
            return true;
308
2.13k
        }
309
2.14k
    };
310
311
2.14k
    for( vlc_tick_t needle_pts = target_pts; ; )
312
2.14k
    {
313
2.14k
        seekpoint_pair_t seekpoints = get_seekpoints_around( needle_pts, priority_tracks );
314
315
2.14k
        Seekpoint const& start = seekpoints.first;
316
2.14k
        Seekpoint const& end   = seekpoints.second;
317
318
2.14k
        if ( start.fpos == std::numeric_limits<fptr_t>::max() )
319
14
            return tracks_seekpoint_t();
320
321
2.13k
        if ( ms.sys.b_fastseekable &&
322
2.13k
             (end.fpos != std::numeric_limits<fptr_t>::max() || !ms.b_cues) &&
323
2.11k
             (needle_pts != start.pts || start.trust_level < Seekpoint::TRUSTED))
324
            // do not read the whole (infinite?) file to get seek indexes
325
            // do not generate an index if we already have the correct seekpoint
326
2.11k
            index_range( ms, Range( start.fpos, end.fpos ), needle_pts );
327
328
2.13k
        tracks_seekpoint_t tpoints = find_greatest_seekpoints_in_range( start.fpos, target_pts, filter_tracks );
329
330
2.13k
        if( contains_all_of_t() ( tpoints, priority_tracks ) )
331
2.12k
            return tpoints;
332
333
        // Avoid busyloop, don't iterate on the same seekpoint
334
8
        if( needle_pts == start.pts - 1 )
335
            // we found the same needle twice, stop looking
336
0
            return tpoints;
337
338
8
        needle_pts = start.pts - 1;
339
8
    }
340
341
0
    vlc_assert_unreachable();
342
0
}
343
344
void
345
SegmentSeeker::index_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts )
346
2.11k
{
347
2.11k
    ranges_t areas_to_search = get_search_areas( search_area.start, search_area.end );
348
349
4.23k
    for( ranges_t::const_iterator range_it = areas_to_search.begin(); range_it != areas_to_search.end(); ++range_it )
350
2.11k
        index_unsearched_range( ms, *range_it, max_pts );
351
2.11k
}
352
353
void
354
SegmentSeeker::index_unsearched_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts )
355
2.11k
{
356
2.11k
    mkv_jump_to( ms, search_area.start );
357
358
2.11k
    search_area.start = ms.es.I_O().getFilePointer();
359
360
2.11k
    fptr_t  block_pos = search_area.start;
361
2.11k
    vlc_tick_t block_pts;
362
363
7.80k
    while( block_pos < search_area.end )
364
7.80k
    {
365
7.80k
        KaxBlock * block;
366
7.80k
        KaxSimpleBlock * simpleblock;
367
7.80k
        KaxBlockAdditions *additions;
368
369
7.80k
        bool     b_key_picture;
370
7.80k
        bool     b_discardable_picture;
371
7.80k
        int64_t  i_block_duration;
372
7.80k
        track_id_t track_id;
373
374
7.80k
        if( ms.BlockGet( block, simpleblock, additions,
375
7.80k
                         &b_key_picture, &b_discardable_picture, &i_block_duration ) )
376
86
        {
377
86
            delete additions;
378
86
            break;
379
86
        }
380
7.71k
        delete additions;
381
382
7.71k
        KaxInternalBlock& internal_block = simpleblock
383
7.71k
            ? static_cast<KaxInternalBlock&>( *simpleblock )
384
7.71k
            : static_cast<KaxInternalBlock&>( *block );
385
386
7.71k
        block_pos = internal_block.GetElementPosition();
387
7.71k
        block_pts = VLC_TICK_FROM_NS(internal_block.GlobalTimestamp());
388
7.71k
        track_id  = internal_block.TrackNum();
389
390
7.71k
        bool const b_valid_track = ms.FindTrackByBlock( block, simpleblock ) != NULL;
391
392
7.71k
        delete block;
393
394
7.71k
        if( b_valid_track )
395
7.71k
        {
396
7.71k
            if( b_key_picture )
397
6.36k
                add_seekpoint( track_id, Seekpoint( block_pos, block_pts ) );
398
399
7.71k
            if( max_pts < block_pts )
400
2.03k
                break;
401
7.71k
        }
402
7.71k
    }
403
404
2.11k
    search_area.end = ms.es.I_O().getFilePointer();
405
406
2.11k
    mark_range_as_searched( search_area );
407
2.11k
}
408
409
void
410
SegmentSeeker::mark_range_as_searched( Range data )
411
10.2k
{
412
    /* TODO: this is utterly ugly, we should do the insertion in-place */
413
414
10.2k
    _ranges_searched.insert( std::upper_bound( _ranges_searched.begin(), _ranges_searched.end(), data ), data );
415
416
10.2k
    {
417
10.2k
        ranges_t merged;
418
419
28.7k
        for( ranges_t::iterator it = _ranges_searched.begin(); it != _ranges_searched.end(); ++it )
420
18.4k
        {
421
18.4k
            if( merged.size() )
422
8.18k
            {
423
8.18k
                Range& last_entry = *merged.rbegin();
424
425
8.18k
                if( last_entry.end+1 >= it->start && last_entry.end < it->end )
426
3.49k
                {
427
3.49k
                    last_entry.end = it->end;
428
3.49k
                    continue;
429
3.49k
                }
430
431
4.68k
                if( it->start >= last_entry.start && it->end <= last_entry.end )
432
4.66k
                {
433
4.66k
                    last_entry.end = std::max( last_entry.end, it->end );
434
4.66k
                    continue;
435
4.66k
                }
436
4.68k
            }
437
438
10.2k
            merged.push_back( *it );
439
10.2k
        }
440
441
10.2k
        _ranges_searched = std::move(merged);
442
10.2k
    }
443
10.2k
}
444
445
446
SegmentSeeker::ranges_t
447
SegmentSeeker::get_search_areas( fptr_t start, fptr_t end ) const
448
2.11k
{
449
2.11k
    ranges_t areas_to_search;
450
2.11k
    Range needle ( start, end );
451
452
2.11k
    ranges_t::const_iterator it = greatest_lower_bound( _ranges_searched.begin(), _ranges_searched.end(), needle );
453
454
2.14k
    for( ; it != _ranges_searched.end() && needle.start < needle.end; ++it )
455
32
    {
456
32
        if( needle.start < it->start )
457
2
        {
458
2
            areas_to_search.push_back( Range( needle.start, it->start ) );
459
2
        }
460
461
32
        if( needle.start <= it->end )
462
28
            needle.start = it->end + 1;
463
32
    }
464
465
2.11k
    needle.start = std::max( needle.start, start );
466
2.11k
    if( it == _ranges_searched.end() && needle.start < needle.end )
467
2.11k
    {
468
2.11k
        areas_to_search.push_back( needle );
469
2.11k
    }
470
471
2.11k
    return areas_to_search;
472
2.11k
}
473
474
void
475
SegmentSeeker::mkv_jump_to( matroska_segment_c& ms, fptr_t fpos )
476
4.24k
{
477
4.24k
    fptr_t i_cluster_pos = -1;
478
479
4.24k
    if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() )
480
4.24k
    {
481
4.24k
        if ( !_cluster_positions.empty() )
482
3.91k
        {
483
3.91k
            cluster_positions_t::iterator cluster_it = greatest_lower_bound(
484
3.91k
              _cluster_positions.begin(), _cluster_positions.end(), fpos
485
3.91k
            );
486
487
3.91k
            ms.es.I_O().setFilePointer( *cluster_it );
488
3.91k
            ms.ep.reconstruct( &ms.es, ms.segment, &ms.sys.demuxer );
489
490
3.91k
            for(;;)
491
4.28k
            {
492
4.28k
                ms.cluster = NULL;
493
4.28k
                EbmlElement *el = ms.ep.Get();
494
4.28k
                if( el == nullptr )
495
10
                {
496
10
                    msg_Err( &ms.sys.demuxer, "unable to read KaxCluster during seek, giving up" );
497
10
                    return;
498
10
                }
499
4.27k
                if (!MKV_IS_ID( el, KaxCluster ))
500
365
                {
501
365
                    ms.cluster = nullptr; // the previous cluster found is not valid anymore
502
365
                    continue; // look for the next element
503
365
                }
504
505
3.91k
                ms.cluster = static_cast<KaxCluster*>( el );
506
507
3.91k
                i_cluster_pos = ms.cluster->GetElementPosition();
508
509
3.91k
                add_cluster_position( i_cluster_pos );
510
511
3.91k
                mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) );
512
513
3.91k
                if ( !ms.cluster->IsFiniteSize() || ms.cluster->GetEndPosition() >= fpos)
514
3.90k
                    break;
515
3.91k
            }
516
3.91k
        }
517
4.24k
    }
518
0
    else if (ms.cluster != NULL)
519
0
    {
520
        // make sure we start reading after the Cluster start
521
0
        ms.es.I_O().setFilePointer(ms.cluster->GetDataStart());
522
0
    }
523
524
4.24k
    assert(ms.ep.GetLevel() == 1);
525
4.23k
    ms.ep.Down();
526
527
    /* read until cluster/timecode to initialize cluster */
528
529
4.27k
    while( EbmlElement * el = ms.ep.Get() )
530
3.93k
    {
531
3.93k
        try {
532
3.93k
            if( MKV_CHECKED_PTR_DECL( p_tc, KaxClusterTimestamp, el ) )
533
3.89k
            {
534
3.89k
                p_tc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA );
535
3.89k
                ms.cluster->InitTimestamp( static_cast<uint64_t>( *p_tc ), ms.i_timescale );
536
3.89k
                add_cluster(ms.cluster);
537
3.89k
                break;
538
3.89k
            }
539
37
            else if( MKV_CHECKED_PTR_DECL( crc, EbmlCrc32, el ) )
540
31
            {
541
31
                crc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); /* avoid a skip that may fail */
542
31
            }
543
3.93k
        }
544
3.93k
        catch(...)
545
3.93k
        {
546
0
            msg_Err( &ms.sys.demuxer,"Error while reading %s",  EBML_NAME(el) );
547
0
        }
548
3.93k
    }
549
550
    /* TODO: add error handling; what if we never get a KaxCluster and/or KaxClusterTimestamp? */
551
552
4.23k
    mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) );
553
554
    /* jump to desired position */
555
556
4.23k
    if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() )
557
4.23k
        ms.es.I_O().setFilePointer( fpos );
558
4.23k
}
559
560
} // namespace