Coverage Report

Created: 2025-12-14 06:40

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
7.18k
    {
38
7.18k
        It it = std::upper_bound( beg, end, value );
39
7.18k
        if( it != beg ) --it;
40
7.18k
        return it;
41
7.18k
    }
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
4.14k
    {
38
4.14k
        It it = std::upper_bound( beg, end, value );
39
4.14k
        if( it != beg ) --it;
40
4.14k
        return it;
41
4.14k
    }
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
1.21k
    {
38
1.21k
        It it = std::upper_bound( beg, end, value );
39
1.21k
        if( it != beg ) --it;
40
1.21k
        return it;
41
1.21k
    }
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
1.83k
    {
38
1.83k
        It it = std::upper_bound( beg, end, value );
39
1.83k
        if( it != beg ) --it;
40
1.83k
        return it;
41
1.83k
    }
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
844
    template<class It> It prev_( It it ) { return --it; }
48
6.39k
    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
4.89k
    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
1.50k
    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
63.2k
{
56
63.2k
    cluster_positions_t::iterator insertion_point = std::upper_bound(
57
63.2k
      _cluster_positions.begin(),
58
63.2k
      _cluster_positions.end(),
59
63.2k
      fpos
60
63.2k
    );
61
62
63.2k
    return _cluster_positions.insert( insertion_point, fpos );
63
63.2k
}
64
65
SegmentSeeker::cluster_map_t::iterator
66
SegmentSeeker::add_cluster( KaxCluster * const p_cluster )
67
4.39k
{
68
4.39k
    Cluster cinfo = {
69
4.39k
        /* fpos     */ p_cluster->GetElementPosition(),
70
4.39k
        /* pts      */ vlc_tick_t( VLC_TICK_FROM_NS( p_cluster->GlobalTimestamp() ) ),
71
4.39k
        /* duration */ vlc_tick_t( -1 ),
72
4.39k
        /* size     */ p_cluster->IsFiniteSize()
73
4.39k
            ? p_cluster->GetEndPosition() - p_cluster->GetElementPosition()
74
4.39k
            : UINT64_MAX
75
4.39k
    };
76
77
4.39k
    add_cluster_position( cinfo.fpos );
78
79
4.39k
    cluster_map_t::iterator it = _clusters.lower_bound( cinfo.pts );
80
81
4.39k
    if( it != _clusters.end() && it->second.pts == cinfo.pts )
82
2.83k
    {
83
        // cluster already known
84
2.83k
    }
85
1.55k
    else
86
1.55k
    {
87
1.55k
        it = _clusters.insert( cluster_map_t::value_type( cinfo.pts, cinfo ) ).first;
88
1.55k
    }
89
90
    // ------------------------------------------------------------------
91
    // IF we have two adjecent clusters, update duration where applicable
92
    // ------------------------------------------------------------------
93
94
4.39k
    struct Duration {
95
4.39k
        static void fix( Cluster& prev, Cluster& next )
96
4.39k
        {
97
1.34k
            if( ( prev.fpos + prev.size) == next.fpos )
98
500
                prev.duration = next.pts - prev.pts;
99
1.34k
        }
100
4.39k
    };
101
102
4.39k
    if( it != _clusters.begin() )
103
844
    {
104
844
        Duration::fix( prev_( it )->second, it->second );
105
844
    }
106
107
4.39k
    if( it != _clusters.end() && next_( it ) != _clusters.end() )
108
503
    {
109
503
        Duration::fix( it->second, next_( it )->second );
110
503
    }
111
112
4.39k
    return it;
113
4.39k
}
114
115
void
116
SegmentSeeker::add_seekpoint( track_id_t track_id, Seekpoint sp )
117
53.5k
{
118
53.5k
    seekpoints_t&  seekpoints = _tracks_seekpoints[ track_id ];
119
53.5k
    seekpoints_t::iterator it = std::lower_bound( seekpoints.begin(), seekpoints.end(), sp );
120
121
53.5k
    if( it != seekpoints.end() && it->fpos == sp.fpos )
122
16.3k
    {
123
16.3k
        if (sp.trust_level <= it->trust_level)
124
16.3k
            return;
125
126
5
        *it = sp;
127
5
    }
128
37.2k
    else if( it != seekpoints.end() && it->pts == sp.pts )
129
6.45k
    {
130
6.45k
        if (sp.trust_level <= it->trust_level)
131
6.21k
            return;
132
133
236
        *it = sp;
134
236
    }
135
30.7k
    else
136
30.7k
    {
137
30.7k
        seekpoints.insert( it, sp );
138
30.7k
    }
139
53.5k
}
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
1.38k
{
144
1.38k
    tracks_seekpoint_t tpoints;
145
146
3.94k
    for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it )
147
2.56k
    {
148
2.56k
        if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() )
149
176
            continue;
150
151
2.39k
        Seekpoint sp = get_first_seekpoint_around( end_pts, it->second );
152
153
2.39k
        if( sp.fpos < start_fpos )
154
227
            continue;
155
156
2.16k
        if( sp.pts > end_pts )
157
14
            continue;
158
159
2.15k
        tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) );
160
2.15k
    }
161
162
1.38k
    if (tpoints.empty())
163
146
    {
164
        // try a further pts
165
395
        for( tracks_seekpoints_t::const_iterator it = _tracks_seekpoints.begin(); it != _tracks_seekpoints.end(); ++it )
166
249
        {
167
249
            if ( std::find( filter_tracks.begin(), filter_tracks.end(), it->first ) == filter_tracks.end() )
168
18
                continue;
169
170
231
            Seekpoint sp = get_first_seekpoint_around( end_pts, it->second );
171
172
231
            if( sp.fpos < start_fpos )
173
217
                continue;
174
175
14
            tpoints.insert( tracks_seekpoint_t::value_type( it->first, sp ) );
176
14
        }
177
146
    }
178
179
1.38k
    return tpoints;
180
1.38k
}
181
182
SegmentSeeker::Seekpoint
183
SegmentSeeker::get_first_seekpoint_around( vlc_tick_t pts, seekpoints_t const& seekpoints,
184
                                           Seekpoint::TrustLevel trust_level )
185
2.62k
{
186
2.62k
    if( seekpoints.empty() )
187
0
    {
188
0
        return Seekpoint();
189
0
    }
190
191
2.62k
    typedef seekpoints_t::const_iterator iterator;
192
193
2.62k
    Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts );
194
195
2.62k
    iterator const it_begin  = seekpoints.begin();
196
2.62k
    iterator const it_end    = seekpoints.end();
197
2.62k
    iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle );
198
199
2.62k
    iterator it_before;
200
201
    // rewrind to _previous_ seekpoint with appropriate trust
202
10.2k
    for( it_before = it_middle; it_before != it_begin; --it_before )
203
8.07k
    {
204
8.07k
        if( it_before->trust_level >= trust_level )
205
470
            return *it_before;
206
8.07k
    }
207
2.15k
    return *it_begin;
208
2.62k
}
209
210
SegmentSeeker::seekpoint_pair_t
211
SegmentSeeker::get_seekpoints_around( vlc_tick_t pts, seekpoints_t const& seekpoints )
212
1.52k
{
213
1.52k
    if( seekpoints.empty() )
214
2
    {
215
2
        return seekpoint_pair_t();
216
2
    }
217
218
1.51k
    typedef seekpoints_t::const_iterator iterator;
219
220
1.51k
    Seekpoint const needle ( std::numeric_limits<fptr_t>::max(), pts );
221
222
1.51k
    iterator const it_begin  = seekpoints.begin();
223
1.51k
    iterator const it_end    = seekpoints.end();
224
1.51k
    iterator const it_middle = greatest_lower_bound( it_begin, it_end, needle );
225
226
1.51k
    if ( it_middle != it_end && (*it_middle).pts > pts)
227
        // found nothing low enough, use the first one
228
18
        return seekpoint_pair_t( *it_begin, Seekpoint() );
229
230
1.50k
    iterator it_before = it_middle;
231
1.50k
    iterator it_after = it_middle == it_end ? it_middle : next_( it_middle ) ;
232
233
1.50k
    return seekpoint_pair_t( *it_before,
234
1.50k
      it_after == it_end ? Seekpoint() : *it_after
235
1.50k
    );
236
1.51k
}
237
238
SegmentSeeker::seekpoint_pair_t
239
SegmentSeeker::get_seekpoints_around( vlc_tick_t target_pts, track_ids_t const& priority_tracks )
240
2.04k
{
241
2.04k
    seekpoint_pair_t points;
242
243
2.04k
    if( _tracks_seekpoints.empty() )
244
469
        return points;
245
246
1.57k
    { // locate the max/min seekpoints for priority_tracks //
247
248
1.57k
        typedef track_ids_t::const_iterator track_iterator;
249
250
1.57k
        track_iterator const begin = priority_tracks.begin();
251
1.57k
        track_iterator const end   = priority_tracks.end();
252
253
3.09k
        for( track_iterator it = begin; it != end; ++it )
254
1.52k
        {
255
1.52k
            seekpoint_pair_t track_points = get_seekpoints_around( target_pts, _tracks_seekpoints[ *it ] );
256
257
1.52k
            if( it == begin ) {
258
1.38k
                points = track_points;
259
1.38k
                continue;
260
1.38k
            }
261
262
139
            if( track_points.first.trust_level > Seekpoint::DISABLED &&
263
139
                points.first.fpos > track_points.first.fpos )
264
2
                points.first = track_points.first;
265
266
139
            if( track_points.second.trust_level > Seekpoint::DISABLED &&
267
17
                points.second.fpos < track_points.second.fpos )
268
4
                points.second = track_points.second;
269
139
        }
270
1.57k
    }
271
272
1.57k
    { // check if we got a cluster which is closer to target_pts than the found cues //
273
274
1.57k
        cluster_map_t::iterator it = _clusters.lower_bound( target_pts );
275
276
1.57k
        if( it != _clusters.begin() && --it != _clusters.end() )
277
89
        {
278
89
            Cluster const& cluster = it->second;
279
280
89
            if( cluster.fpos > points.first.fpos )
281
14
            {
282
14
                points.first = Seekpoint( cluster.fpos, cluster.pts );
283
284
                // do we need to update the max point? //
285
286
14
                if( points.second.fpos < points.first.fpos )
287
0
                    points.second = Seekpoint( cluster.fpos + cluster.size, cluster.pts + cluster.duration );
288
14
            }
289
89
        }
290
1.57k
    }
291
292
1.57k
    return points;
293
2.04k
}
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
1.90k
{
299
1.90k
    struct contains_all_of_t {
300
1.90k
        bool operator()( tracks_seekpoint_t const& haystack, track_ids_t const& track_ids )
301
1.90k
        {
302
2.74k
            for( track_ids_t::const_iterator it = track_ids.begin(); it != track_ids.end(); ++it ) {
303
1.50k
                if( haystack.find( *it ) == haystack.end() )
304
142
                    return false;
305
1.50k
            }
306
307
1.23k
            return true;
308
1.38k
        }
309
1.90k
    };
310
311
1.90k
    for( vlc_tick_t needle_pts = target_pts; ; )
312
2.04k
    {
313
2.04k
        seekpoint_pair_t seekpoints = get_seekpoints_around( needle_pts, priority_tracks );
314
315
2.04k
        Seekpoint const& start = seekpoints.first;
316
2.04k
        Seekpoint const& end   = seekpoints.second;
317
318
2.04k
        if ( start.fpos == std::numeric_limits<fptr_t>::max() )
319
663
            return tracks_seekpoint_t();
320
321
1.38k
        if ( (end.fpos != std::numeric_limits<fptr_t>::max() || !ms.b_cues) &&
322
1.21k
             (needle_pts != start.pts || start.trust_level < Seekpoint::TRUSTED))
323
            // do not read the whole (infinite?) file to get seek indexes
324
            // do not generate an index if we already have the correct seekpoint
325
1.21k
            index_range( ms, Range( start.fpos, end.fpos ), needle_pts );
326
327
1.38k
        tracks_seekpoint_t tpoints = find_greatest_seekpoints_in_range( start.fpos, target_pts, filter_tracks );
328
329
1.38k
        if( contains_all_of_t() ( tpoints, priority_tracks ) )
330
1.23k
            return tpoints;
331
332
        // Avoid busyloop, don't iterate on the same seekpoint
333
142
        if( needle_pts == start.pts - 1 )
334
            // we found the same needle twice, stop looking
335
4
            return tpoints;
336
337
138
        needle_pts = start.pts - 1;
338
138
    }
339
340
0
    vlc_assert_unreachable();
341
0
}
342
343
void
344
SegmentSeeker::index_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts )
345
1.21k
{
346
1.21k
    ranges_t areas_to_search = get_search_areas( search_area.start, search_area.end );
347
348
2.44k
    for( ranges_t::const_iterator range_it = areas_to_search.begin(); range_it != areas_to_search.end(); ++range_it )
349
1.23k
        index_unsearched_range( ms, *range_it, max_pts );
350
1.21k
}
351
352
void
353
SegmentSeeker::index_unsearched_range( matroska_segment_c& ms, Range search_area, vlc_tick_t max_pts )
354
1.23k
{
355
1.23k
    mkv_jump_to( ms, search_area.start );
356
357
1.23k
    search_area.start = ms.es.I_O().getFilePointer();
358
359
1.23k
    fptr_t  block_pos = search_area.start;
360
1.23k
    vlc_tick_t block_pts;
361
362
2.71k
    while( block_pos < search_area.end )
363
2.63k
    {
364
2.63k
        KaxBlock * block;
365
2.63k
        KaxSimpleBlock * simpleblock;
366
2.63k
        KaxBlockAdditions *additions;
367
368
2.63k
        bool     b_key_picture;
369
2.63k
        bool     b_discardable_picture;
370
2.63k
        int64_t  i_block_duration;
371
2.63k
        track_id_t track_id;
372
373
2.63k
        if( ms.BlockGet( block, simpleblock, additions,
374
2.63k
                         &b_key_picture, &b_discardable_picture, &i_block_duration ) )
375
631
        {
376
631
            delete additions;
377
631
            break;
378
631
        }
379
2.00k
        delete additions;
380
381
2.00k
        KaxInternalBlock& internal_block = simpleblock
382
2.00k
            ? static_cast<KaxInternalBlock&>( *simpleblock )
383
2.00k
            : static_cast<KaxInternalBlock&>( *block );
384
385
2.00k
        block_pos = internal_block.GetElementPosition();
386
2.00k
        block_pts = VLC_TICK_FROM_NS(internal_block.GlobalTimestamp());
387
2.00k
        track_id  = internal_block.TrackNum();
388
389
2.00k
        bool const b_valid_track = ms.FindTrackByBlock( block, simpleblock ) != NULL;
390
391
2.00k
        delete block;
392
393
2.00k
        if( b_valid_track )
394
2.00k
        {
395
2.00k
            if( b_key_picture )
396
783
                add_seekpoint( track_id, Seekpoint( block_pos, block_pts ) );
397
398
2.00k
            if( max_pts < block_pts )
399
525
                break;
400
2.00k
        }
401
2.00k
    }
402
403
1.23k
    search_area.end = ms.es.I_O().getFilePointer();
404
405
1.23k
    mark_range_as_searched( search_area );
406
1.23k
}
407
408
void
409
SegmentSeeker::mark_range_as_searched( Range data )
410
4.67k
{
411
    /* TODO: this is utterly ugly, we should do the insertion in-place */
412
413
4.67k
    _ranges_searched.insert( std::upper_bound( _ranges_searched.begin(), _ranges_searched.end(), data ), data );
414
415
4.67k
    {
416
4.67k
        ranges_t merged;
417
418
12.9k
        for( ranges_t::iterator it = _ranges_searched.begin(); it != _ranges_searched.end(); ++it )
419
8.23k
        {
420
8.23k
            if( merged.size() )
421
3.56k
            {
422
3.56k
                Range& last_entry = *merged.rbegin();
423
424
3.56k
                if( last_entry.end+1 >= it->start && last_entry.end < it->end )
425
1.31k
                {
426
1.31k
                    last_entry.end = it->end;
427
1.31k
                    continue;
428
1.31k
                }
429
430
2.25k
                if( it->start >= last_entry.start && it->end <= last_entry.end )
431
2.17k
                {
432
2.17k
                    last_entry.end = std::max( last_entry.end, it->end );
433
2.17k
                    continue;
434
2.17k
                }
435
2.25k
            }
436
437
4.74k
            merged.push_back( *it );
438
4.74k
        }
439
440
4.67k
        _ranges_searched = std::move(merged);
441
4.67k
    }
442
4.67k
}
443
444
445
SegmentSeeker::ranges_t
446
SegmentSeeker::get_search_areas( fptr_t start, fptr_t end ) const
447
1.21k
{
448
1.21k
    ranges_t areas_to_search;
449
1.21k
    Range needle ( start, end );
450
451
1.21k
    ranges_t::const_iterator it = greatest_lower_bound( _ranges_searched.begin(), _ranges_searched.end(), needle );
452
453
1.37k
    for( ; it != _ranges_searched.end() && needle.start < needle.end; ++it )
454
160
    {
455
160
        if( needle.start < it->start )
456
97
        {
457
97
            areas_to_search.push_back( Range( needle.start, it->start ) );
458
97
        }
459
460
160
        if( needle.start <= it->end )
461
123
            needle.start = it->end + 1;
462
160
    }
463
464
1.21k
    needle.start = std::max( needle.start, start );
465
1.21k
    if( it == _ranges_searched.end() && needle.start < needle.end )
466
1.14k
    {
467
1.14k
        areas_to_search.push_back( needle );
468
1.14k
    }
469
470
1.21k
    return areas_to_search;
471
1.21k
}
472
473
void
474
SegmentSeeker::mkv_jump_to( matroska_segment_c& ms, fptr_t fpos )
475
2.47k
{
476
2.47k
    fptr_t i_cluster_pos = -1;
477
478
2.47k
    if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() )
479
2.47k
    {
480
2.47k
        ms.cluster = NULL;
481
2.47k
        if ( !_cluster_positions.empty() )
482
1.83k
        {
483
1.83k
            cluster_positions_t::iterator cluster_it = greatest_lower_bound(
484
1.83k
              _cluster_positions.begin(), _cluster_positions.end(), fpos
485
1.83k
            );
486
487
1.83k
            ms.es.I_O().setFilePointer( *cluster_it );
488
1.83k
            ms.ep.reconstruct( &ms.es, ms.segment, &ms.sys.demuxer );
489
1.83k
        }
490
491
15.5k
        while( ms.cluster == NULL || (
492
1.71k
              ms.cluster->IsFiniteSize() && ms.cluster->GetEndPosition() < fpos ) )
493
13.8k
        {
494
13.8k
            EbmlElement *el = ms.ep.Get();
495
13.8k
            if( el == nullptr )
496
762
            {
497
762
                msg_Err( &ms.sys.demuxer, "unable to read KaxCluster during seek, giving up" );
498
762
                return;
499
762
            }
500
13.0k
            if (!MKV_IS_ID( el, KaxCluster ))
501
11.3k
                continue; // look for the next element
502
503
1.71k
            ms.cluster = static_cast<KaxCluster*>( el );
504
505
1.71k
            i_cluster_pos = ms.cluster->GetElementPosition();
506
507
1.71k
            add_cluster_position( i_cluster_pos );
508
509
1.71k
            mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) );
510
1.71k
        }
511
2.47k
    }
512
0
    else if (ms.cluster != NULL)
513
0
    {
514
        // make sure we start reading after the Cluster start
515
0
        ms.es.I_O().setFilePointer(ms.cluster->GetDataStart());
516
0
    }
517
518
1.71k
    ms.ep.Down();
519
520
    /* read until cluster/timecode to initialize cluster */
521
522
2.15k
    while( EbmlElement * el = ms.ep.Get() )
523
2.04k
    {
524
2.04k
        try {
525
2.04k
            if( MKV_CHECKED_PTR_DECL( p_tc, KaxClusterTimestamp, el ) )
526
1.61k
            {
527
1.61k
                p_tc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA );
528
1.61k
                ms.cluster->InitTimestamp( static_cast<uint64_t>( *p_tc ), ms.i_timescale );
529
1.61k
                add_cluster(ms.cluster);
530
1.61k
                break;
531
1.61k
            }
532
429
            else if( MKV_CHECKED_PTR_DECL( crc, EbmlCrc32, el ) )
533
90
            {
534
90
                crc->ReadData( ms.es.I_O(), SCOPE_ALL_DATA ); /* avoid a skip that may fail */
535
90
            }
536
2.04k
        }
537
2.04k
        catch(...)
538
2.04k
        {
539
14
            msg_Err( &ms.sys.demuxer,"Error while reading %s",  EBML_NAME(el) );
540
14
        }
541
2.04k
    }
542
543
    /* TODO: add error handling; what if we never get a KaxCluster and/or KaxClusterTimestamp? */
544
545
1.73k
    mark_range_as_searched( Range( i_cluster_pos, ms.es.I_O().getFilePointer() ) );
546
547
    /* jump to desired position */
548
549
1.73k
    if ( fpos != std::numeric_limits<SegmentSeeker::fptr_t>::max() )
550
1.71k
        ms.es.I_O().setFilePointer( fpos );
551
1.73k
}
552
553
} // namespace