Coverage Report

Created: 2026-02-14 08:08

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