Coverage Report

Created: 2026-06-30 07:56

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