Coverage Report

Created: 2026-07-12 08:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mkv/matroska_segment.cpp
Line
Count
Source
1
/*****************************************************************************
2
 * matroska_segment.cpp : matroska demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2003-2010 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *          Steve Lhomme <steve.lhomme@free.fr>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
#include "matroska_segment.hpp"
25
#include "chapters.hpp"
26
#include "demux.hpp"
27
#include "util.hpp"
28
#include "Ebml_dispatcher.hpp"
29
30
#include <vlc_arrays.h>
31
32
#include <new>
33
#include <iterator>
34
#include <limits>
35
36
namespace mkv {
37
38
matroska_segment_c::matroska_segment_c( demux_sys_t & demuxer, matroska_iostream_c & estream, KaxSegment *p_seg )
39
2.19k
    :segment(p_seg)
40
2.19k
    ,es(estream)
41
2.19k
    ,i_timescale(MKVD_TIMECODESCALE)
42
2.19k
    ,i_duration(-1)
43
2.19k
    ,i_mk_start_time(0)
44
2.19k
    ,i_seekhead_count(0)
45
2.19k
    ,i_seekhead_position(-1)
46
2.19k
    ,i_cues_position(-1)
47
2.19k
    ,i_tracks_position(-1)
48
2.19k
    ,i_info_position(-1)
49
2.19k
    ,i_chapters_position(-1)
50
2.19k
    ,i_attachments_position(-1)
51
2.19k
    ,cluster(NULL)
52
2.19k
    ,i_block_pos(0)
53
2.19k
    ,p_segment_uid(NULL)
54
2.19k
    ,p_prev_segment_uid(NULL)
55
2.19k
    ,p_next_segment_uid(NULL)
56
2.19k
    ,b_cues(false)
57
2.19k
    ,psz_muxing_application(NULL)
58
2.19k
    ,psz_writing_application(NULL)
59
2.19k
    ,psz_title(NULL)
60
2.19k
    ,i_default_edition(0)
61
2.19k
    ,sys(demuxer)
62
2.19k
    ,ep( EbmlParser(&estream, p_seg, &demuxer.demuxer ))
63
2.19k
    ,b_preloaded(false)
64
2.19k
    ,b_ref_external_segments(false)
65
2.19k
{
66
2.19k
}
67
68
matroska_segment_c::~matroska_segment_c()
69
2.19k
{
70
2.19k
    free( psz_writing_application );
71
2.19k
    free( psz_muxing_application );
72
2.19k
    free( psz_title );
73
74
2.19k
    delete segment;
75
2.19k
    delete p_segment_uid;
76
2.19k
    delete p_prev_segment_uid;
77
2.19k
    delete p_next_segment_uid;
78
79
2.19k
    vlc_delete_all( stored_editions );
80
2.19k
    vlc_delete_all( translations );
81
2.19k
    vlc_delete_all( families );
82
2.19k
}
83
84
85
/*****************************************************************************
86
 * Tools                                                                     *
87
 *****************************************************************************
88
 *  * LoadCues : load the cues element and update index
89
 *  * LoadTags : load ... the tags element
90
 *  * InformationCreate : create all information, load tags if present
91
 *****************************************************************************/
92
void matroska_segment_c::LoadCues( KaxCues *cues )
93
114
{
94
114
    EbmlElement *el;
95
96
114
    if( b_cues )
97
0
    {
98
0
        msg_Warn( &sys.demuxer, "There can be only 1 Cues per section." );
99
0
        return;
100
0
    }
101
102
114
    EbmlParser eparser (&es, cues, &sys.demuxer );
103
2.80k
    while( ( el = eparser.Get() ) != NULL )
104
2.69k
    {
105
2.69k
        if( MKV_IS_ID( el, KaxCuePoint ) )
106
2.59k
        {
107
2.59k
            uint64_t cue_position = -1;
108
2.59k
            vlc_tick_t  cue_mk_time = -1;
109
110
2.59k
            unsigned int track_id = 0;
111
2.59k
            bool b_invalid_cue = false;
112
113
2.59k
            eparser.Down();
114
7.67k
            while( ( el = eparser.Get() ) != NULL )
115
5.08k
            {
116
5.08k
                if ( MKV_CHECKED_PTR_DECL( cuetime, KaxCueTime, el ) )
117
2.56k
                {
118
2.56k
                    try
119
2.56k
                    {
120
2.56k
                        if( unlikely( !cuetime->ValidateSize() ) )
121
0
                        {
122
0
                            msg_Err( &sys.demuxer, "CueTime size too big");
123
0
                            b_invalid_cue = true;
124
0
                            break;
125
0
                        }
126
2.56k
                        cuetime->ReadData( es.I_O() );
127
2.56k
                    }
128
2.56k
                    catch(...)
129
2.56k
                    {
130
0
                        msg_Err( &sys.demuxer, "Error while reading CueTime" );
131
0
                        b_invalid_cue = true;
132
0
                        break;
133
0
                    }
134
2.56k
                    cue_mk_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( *cuetime ) * i_timescale);
135
2.56k
                }
136
2.52k
                else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
137
2.52k
                {
138
2.52k
                    eparser.Down();
139
2.52k
                    try
140
2.52k
                    {
141
7.77k
                        while( ( el = eparser.Get() ) != NULL )
142
5.25k
                        {
143
5.25k
                            if( unlikely( !el->ValidateSize() ) )
144
0
                            {
145
0
                                eparser.Up();
146
0
                                msg_Err( &sys.demuxer, "Error %s too big, aborting", EBML_NAME(el) );
147
0
                                b_invalid_cue = true;
148
0
                                break;
149
0
                            }
150
151
5.25k
                            if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) )
152
2.51k
                            {
153
2.51k
                                kct_ptr->ReadData( es.I_O() );
154
2.51k
                                track_id = static_cast<uint16_t>( *kct_ptr );
155
2.51k
                            }
156
2.73k
                            else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) )
157
2.51k
                            {
158
2.51k
                                kccp_ptr->ReadData( es.I_O() );
159
2.51k
                                cue_position = segment->GetGlobalPosition( static_cast<uint64_t>( *kccp_ptr ) );
160
161
2.51k
                                _seeker.add_cluster_position( cue_position );
162
2.51k
                            }
163
226
                            else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) )
164
0
                            {
165
0
                                VLC_UNUSED( kcbn_ptr );
166
0
                            }
167
226
#if LIBMATROSKA_VERSION >= 0x010401
168
226
                            else if( MKV_CHECKED_PTR_DECL( cuerelative, KaxCueRelativePosition, el ) )
169
218
                            {
170
218
                                VLC_UNUSED( cuerelative );
171
218
                            }
172
8
                            else if( MKV_CHECKED_PTR_DECL( cueblock, KaxCueBlockNumber, el ) )
173
0
                            {
174
0
                                VLC_UNUSED( cueblock );
175
0
                            }
176
8
                            else if( MKV_CHECKED_PTR_DECL( cueref, KaxCueReference, el ) )
177
0
                            {
178
0
                                VLC_UNUSED( cueref );
179
0
                            }
180
8
                            else if( MKV_CHECKED_PTR_DECL( cueduration, KaxCueDuration, el ) )
181
8
                            {
182
8
                                VLC_UNUSED( cueduration );
183
8
                            }
184
0
#endif
185
0
                            else
186
0
                            {
187
0
                                msg_Dbg( &sys.demuxer, "         * Unknown (%s)", EBML_NAME(el) );
188
0
                            }
189
5.25k
                        }
190
2.52k
                    }
191
2.52k
                    catch(...)
192
2.52k
                    {
193
0
                        eparser.Up();
194
0
                        msg_Err( &sys.demuxer, "Error while reading %s", EBML_NAME(el) );
195
0
                        b_invalid_cue = true;
196
0
                        break;
197
0
                    }
198
2.52k
                    eparser.Up();
199
2.52k
                }
200
3
                else
201
3
                {
202
3
                    msg_Dbg( &sys.demuxer, "     * Unknown (%s)", EBML_NAME(el) );
203
3
                }
204
5.08k
            }
205
2.59k
            eparser.Up();
206
207
2.59k
            if( track_id != 0 && cue_mk_time != -1 && cue_position != static_cast<uint64_t>( -1 ) ) {
208
209
2.50k
                SegmentSeeker::Seekpoint::TrustLevel level = SegmentSeeker::Seekpoint::DISABLED;
210
211
2.50k
                if( ! b_invalid_cue && tracks.find( track_id ) != tracks.end() )
212
2.39k
                {
213
2.39k
                    level = sys.trust_cues ?
214
0
                            SegmentSeeker::Seekpoint::TRUSTED :
215
2.39k
                            SegmentSeeker::Seekpoint::QUESTIONABLE;
216
2.39k
                }
217
218
2.50k
                _seeker.add_seekpoint( track_id,
219
2.50k
                    SegmentSeeker::Seekpoint( cue_position, cue_mk_time, level ) );
220
2.50k
            }
221
2.59k
        }
222
102
        else
223
102
        {
224
102
            msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) );
225
102
        }
226
2.69k
    }
227
114
    b_cues = true;
228
114
    msg_Dbg( &sys.demuxer, "|   - loading cues done." );
229
114
}
230
231
232
static const struct {
233
    vlc_meta_type_t type;
234
    const char *key;
235
    int target_type; /* 0 is valid for all target_type */
236
} metadata_map[] = {
237
                     {vlc_meta_ShowName,    "TITLE",         70},
238
                     {vlc_meta_Album,       "TITLE",         50},
239
                     {vlc_meta_Title,       "TITLE",         30},
240
                     {vlc_meta_DiscNumber,  "PART_NUMBER",   60},
241
                     {vlc_meta_Season,      "PART_NUMBER",   60},
242
                     {vlc_meta_Episode,     "PART_NUMBER",   50},
243
                     {vlc_meta_TrackNumber, "PART_NUMBER",   30},
244
                     {vlc_meta_DiscTotal,   "TOTAL_PARTS",   70},
245
                     {vlc_meta_TrackTotal,  "TOTAL_PARTS",   30},
246
                     {vlc_meta_Setting,     "ENCODER_SETTINGS", 0},
247
                     /* TODO read TagLanguage {vlc_meta_Language} */
248
                     /* TODO read tags targeting attachments {vlc_meta_ArtworkURL, */
249
                     {vlc_meta_AlbumArtist, "ARTIST",        50},
250
                     {vlc_meta_Artist,      "ARTIST",        0},
251
                     {vlc_meta_Director,    "DIRECTOR",      0},
252
                     {vlc_meta_Actors,      "ACTOR",         0},
253
                     {vlc_meta_Genre,       "GENRE",         0},
254
                     {vlc_meta_Copyright,   "COPYRIGHT",     0},
255
                     {vlc_meta_Description, "DESCRIPTION",   0},
256
                     {vlc_meta_Description, "COMMENT",       0},
257
                     {vlc_meta_Rating,      "RATING",        0},
258
                     {vlc_meta_Date,        "DATE_RELEASED", 0},
259
                     {vlc_meta_Date,        "DATE_RELEASE",  0},
260
                     {vlc_meta_Date,        "DATE_RECORDED", 0},
261
                     {vlc_meta_URL,         "URL",           0},
262
                     {vlc_meta_Publisher,   "PUBLISHER",     0},
263
                     {vlc_meta_EncodedBy,   "ENCODED_BY",    0},
264
                     {vlc_meta_Album,       "ALBUM",         0}, /* invalid tag */
265
                     {vlc_meta_Title,       NULL,            0},
266
};
267
268
bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type )
269
315
{
270
315
    msg_Dbg( &sys.demuxer, "|   + Simple Tag ");
271
315
    struct SimpleTagHandlerPayload
272
315
    {
273
315
        matroska_segment_c * const obj;
274
315
        EbmlParser         * const ep;
275
315
        demux_sys_t        & sys;
276
315
        SimpleTag          & out;
277
315
        int                target_type;
278
315
    } payload = { this, &ep, sys, *pout_simple, 50 };
279
315
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, SimpleTagHandler, SimpleTagHandlerPayload )
280
315
    {
281
315
        MKV_SWITCH_INIT();
282
315
        E_CASE( KaxTagName, entry )
283
315
        {
284
236
            vars.out.tag_name = UTFstring( entry ).GetUTF8().c_str();
285
236
        }
286
315
        E_CASE( KaxTagString, entry )
287
315
        {
288
234
            vars.out.value = UTFstring( entry ).GetUTF8().c_str();
289
234
        }
290
315
        E_CASE( KaxTagLangue, entry )
291
315
        {
292
14
            vars.out.lang = entry.GetValue();
293
14
        }
294
315
        E_CASE( KaxTagDefault, unused )
295
315
        {
296
0
            VLC_UNUSED(unused);
297
0
            VLC_UNUSED(vars);
298
0
        }
299
315
        E_CASE( KaxTagSimple, simple )
300
315
        {
301
0
            SimpleTag st; // ParseSimpleTags will write to this variable
302
                          // the SimpleTag is valid if ParseSimpleTags returns `true`
303
304
0
            if (vars.obj->ParseSimpleTags( &st, &simple, vars.target_type ))
305
0
              vars.out.sub_tags.push_back( std::move(st) );
306
0
        }
307
315
    };
308
315
    SimpleTagHandler::Dispatcher().iterate( tag->begin(), tag->end(), &payload );
309
310
315
    if( pout_simple->tag_name.empty() )
311
79
    {
312
79
        msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found.");
313
79
        return false;
314
79
    }
315
236
    if( !sys.meta )
316
72
        sys.meta = vlc_meta_New();
317
4.00k
    for( int i = 0; metadata_map[i].key; i++ )
318
3.93k
    {
319
3.93k
        if( pout_simple->tag_name == metadata_map[i].key &&
320
230
            (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) )
321
171
        {
322
171
            vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () );
323
171
            msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
324
171
            goto done;
325
171
        }
326
3.93k
    }
327
65
    msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
328
65
    vlc_meta_SetExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
329
236
done:
330
236
    return true;
331
65
}
332
333
void matroska_segment_c::LoadTags( KaxTags *tags_ )
334
462
{
335
462
    if ( !ReadMaster( *tags_ ) )
336
48
        return;
337
338
414
    struct TagsHandlerPayload
339
414
    {
340
414
        matroska_segment_c * const obj;
341
414
        EbmlParser         * const ep;
342
414
        demux_sys_t        & sys;
343
414
        int                target_type;
344
414
    } payload = { this, &ep, sys, 50 };
345
414
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxTagsHandler, TagsHandlerPayload )
346
414
    {
347
414
        MKV_SWITCH_INIT();
348
414
        E_CASE( KaxTag, entry )
349
414
        {
350
174
            msg_Dbg( &vars.sys.demuxer, "+ Tag" );
351
174
            Tag tag;
352
174
            struct TagHandlerPayload
353
174
            {
354
174
                matroska_segment_c * const obj;
355
174
                EbmlParser         * const ep;
356
174
                demux_sys_t        & sys;
357
174
                Tag                & tag;
358
174
                int                target_type;
359
174
            } payload = { vars.obj, vars.ep, vars.sys, tag, 50 };
360
174
            MKV_SWITCH_CREATE( EbmlTypeDispatcher, TagHandler, TagHandlerPayload )
361
174
            {
362
174
                MKV_SWITCH_INIT();
363
174
                E_CASE( KaxTagTargets, targets )
364
174
                {
365
172
                    msg_Dbg( &vars.sys.demuxer, "|   + Targets" );
366
367
172
                    MKV_SWITCH_CREATE( EbmlTypeDispatcher, TargetsHandler, TagHandlerPayload )
368
172
                    {
369
172
                        MKV_SWITCH_INIT();
370
172
                        E_CASE( KaxTagTargetTypeValue, entry )
371
172
                        {
372
4
                            vars.target_type = static_cast<uint32_t>( entry );
373
4
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TargetTypeValue: %u", vars.target_type);
374
4
                        }
375
172
                        E_CASE( KaxTagTrackUID, entry )
376
172
                        {
377
28
                            vars.tag.i_tag_type = TRACK_UID;
378
28
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
379
28
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TrackUID: %" PRIu64, vars.tag.i_uid);
380
28
                        }
381
172
                        E_CASE( KaxTagEditionUID, entry )
382
172
                        {
383
0
                            vars.tag.i_tag_type = EDITION_UID;
384
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
385
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + EditionUID: %" PRIu64, vars.tag.i_uid);
386
0
                        }
387
172
                        E_CASE( KaxTagChapterUID, entry )
388
172
                        {
389
0
                            vars.tag.i_tag_type = CHAPTER_UID;
390
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
391
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + ChapterUID: %" PRIu64, vars.tag.i_uid);
392
0
                        }
393
172
                        E_CASE( KaxTagAttachmentUID, entry )
394
172
                        {
395
0
                            vars.tag.i_tag_type = ATTACHMENT_UID;
396
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
397
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + AttachmentUID: %" PRIu64, vars.tag.i_uid);
398
0
                        }
399
172
                        E_CASE( KaxTagTargetType, entry )
400
172
                        {
401
2
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TargetType: %s", entry.GetValue().c_str());
402
2
                        }
403
172
                        E_CASE_DEFAULT( el )
404
172
                        {
405
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
406
0
                        }
407
172
                    };
408
409
172
                    TargetsHandler::Dispatcher().iterate( targets.begin(), targets.end(), &vars );
410
172
                }
411
174
                E_CASE( KaxTagSimple, entry )
412
315
                {
413
315
                    SimpleTag simple;
414
415
315
                    if (vars.obj->ParseSimpleTags( &simple, &entry, vars.target_type ))
416
236
                        vars.tag.simple_tags.push_back( std::move(simple) );
417
315
                }
418
174
                E_CASE_DEFAULT( el )
419
301
                {
420
301
                    msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
421
301
                }
422
174
            };
423
424
174
            TagHandler::Dispatcher().iterate( entry.begin(), entry.end(), &payload );
425
174
            vars.obj->tags.push_back(std::move(tag));
426
174
        }
427
414
        E_CASE_DEFAULT( el )
428
689
        {
429
689
            msg_Dbg( &vars.sys.demuxer, "|   + LoadTag Unknown (%s)", EBML_NAME(&el) );
430
689
        }
431
414
    };
432
433
414
    KaxTagsHandler::Dispatcher().iterate( tags_->begin(), tags_->end(), &payload );
434
414
    msg_Dbg( &sys.demuxer, "loading tags done." );
435
414
}
436
437
/*****************************************************************************
438
 * InformationCreate:
439
 *****************************************************************************/
440
void matroska_segment_c::InformationCreate( )
441
2.15k
{
442
2.15k
    if( !sys.meta )
443
2.07k
        sys.meta = vlc_meta_New();
444
445
2.15k
    if( psz_title )
446
183
    {
447
183
        vlc_meta_SetTitle( sys.meta, psz_title );
448
183
    }
449
2.15k
}
450
451
452
/*****************************************************************************
453
 * Misc
454
 *****************************************************************************/
455
456
bool matroska_segment_c::PreloadClusters(uint64_t i_cluster_pos)
457
0
{
458
0
    struct ClusterHandlerPayload
459
0
    {
460
0
        matroska_segment_c * const obj;
461
0
        bool stop_parsing;
462
463
0
    } payload = { this, false };
464
465
0
    MKV_SWITCH_CREATE(EbmlTypeDispatcher, ClusterHandler, ClusterHandlerPayload )
466
0
    {
467
0
        MKV_SWITCH_INIT();
468
469
0
        E_CASE( KaxCluster, kcluster )
470
0
        {
471
0
            vars.obj->ParseCluster( &kcluster, false );
472
0
        }
473
474
0
        E_CASE_DEFAULT( el )
475
0
        {
476
0
            VLC_UNUSED( el );
477
0
            vars.stop_parsing = true;
478
0
        }
479
0
    };
480
481
0
    {
482
0
        es.I_O().setFilePointer( i_cluster_pos );
483
484
0
        while (payload.stop_parsing == false)
485
0
        {
486
0
            EbmlParser parser ( &es, segment, &sys.demuxer );
487
0
            EbmlElement* el = parser.Get();
488
489
0
            if( el == NULL )
490
0
                break;
491
492
0
            ClusterHandler::Dispatcher().send( el, &payload );
493
0
        }
494
0
    }
495
496
0
    return true;
497
0
}
498
499
bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment )
500
0
{
501
0
    if ( b_preloaded )
502
0
        return false;
503
504
0
    if ( SameFamily( of_segment ) )
505
0
        return Preload( );
506
507
0
    return false;
508
0
}
509
510
bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
511
0
{
512
0
    EbmlBinary *p_tmp;
513
514
0
    if ( p_item_a == NULL || p_item_b == NULL )
515
0
        return false;
516
517
0
    p_tmp = static_cast<EbmlBinary *>( p_item_a->p_segment_uid );
518
0
    if ( !p_tmp )
519
0
        return false;
520
0
    if ( p_item_b->p_prev_segment_uid != NULL
521
0
          && *p_tmp == *p_item_b->p_prev_segment_uid )
522
0
        return true;
523
524
0
    p_tmp = static_cast<EbmlBinary *>( p_item_a->p_next_segment_uid );
525
0
    if ( !p_tmp )
526
0
        return false;
527
528
0
    if ( p_item_b->p_segment_uid != NULL
529
0
          && *p_tmp == *p_item_b->p_segment_uid )
530
0
        return true;
531
532
0
    if ( p_item_b->p_prev_segment_uid != NULL
533
0
          && *p_tmp == *p_item_b->p_prev_segment_uid )
534
0
        return true;
535
536
0
    return false;
537
0
}
538
539
bool matroska_segment_c::SameFamily( const matroska_segment_c & of_segment ) const
540
0
{
541
0
    for (size_t i=0; i<families.size(); i++)
542
0
    {
543
0
        for (size_t j=0; j<of_segment.families.size(); j++)
544
0
        {
545
0
            if ( *(families[i]) == *(of_segment.families[j]) )
546
0
                return true;
547
0
        }
548
0
    }
549
0
    return false;
550
0
}
551
552
bool matroska_segment_c::Preload( )
553
6.39k
{
554
6.39k
    if ( b_preloaded )
555
4.19k
        return false;
556
557
2.19k
    EbmlElement *el = NULL;
558
559
2.19k
    ep.Reset( &sys.demuxer );
560
561
11.5k
    while( ( el = ep.Get() ) != NULL )
562
11.5k
    {
563
11.5k
        if( MKV_IS_ID( el, KaxSeekHead ) )
564
1.47k
        {
565
            /* Multiple allowed */
566
            /* We bail at 10, to prevent possible recursion */
567
1.47k
            msg_Dbg(  &sys.demuxer, "|   + Seek head" );
568
1.47k
            if( i_seekhead_count < 10 )
569
1.47k
            {
570
1.47k
                i_seekhead_position = el->GetElementPosition();
571
1.47k
                ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
572
1.47k
            }
573
1.47k
        }
574
10.0k
        else if( MKV_IS_ID( el, KaxInfo ) )
575
1.40k
        {
576
            /* Multiple allowed, mandatory */
577
1.40k
            msg_Dbg(  &sys.demuxer, "|   + Information" );
578
1.40k
            if( i_info_position < 0 )
579
746
            {
580
746
                ParseInfo( static_cast<KaxInfo*>( el ) );
581
746
                i_info_position = el->GetElementPosition();
582
746
            }
583
1.40k
        }
584
8.65k
        else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) )
585
2.45k
        {
586
            /* Multiple allowed */
587
2.45k
            msg_Dbg(  &sys.demuxer, "|   + Tracks" );
588
2.45k
            if( i_tracks_position < 0 )
589
1.61k
            {
590
1.61k
                ParseTracks( kt_ptr );
591
1.61k
            }
592
2.45k
            if ( tracks.size() == 0 )
593
4
            {
594
4
                msg_Err( &sys.demuxer, "No tracks supported" );
595
4
            }
596
2.45k
            i_tracks_position = el->GetElementPosition();
597
2.45k
        }
598
6.19k
        else if( MKV_CHECKED_PTR_DECL ( cues, KaxCues, el ) )
599
341
        {
600
341
            msg_Dbg(  &sys.demuxer, "|   + Cues" );
601
341
            if( i_cues_position < 0 )
602
55
            {
603
55
                LoadCues( cues );
604
55
                i_cues_position = el->GetElementPosition();
605
55
            }
606
341
        }
607
5.85k
        else if( MKV_CHECKED_PTR_DECL ( cluster_, KaxCluster, el ) )
608
2.17k
        {
609
2.17k
            if( sys.b_seekable &&
610
2.17k
                var_InheritBool( &sys.demuxer, "mkv-preload-clusters" ) )
611
0
            {
612
0
                PreloadClusters        ( cluster_->GetElementPosition() );
613
0
                es.I_O().setFilePointer( cluster_->GetElementPosition() );
614
0
            }
615
2.17k
            msg_Dbg( &sys.demuxer, "|   + Cluster" );
616
617
618
2.17k
            if (EnsureDuration(*cluster_))
619
2.16k
            {
620
2.16k
                cluster = cluster_;
621
622
                // add first cluster as trusted seekpoint for all tracks
623
2.16k
                for( tracks_map_t::const_iterator it = tracks.begin();
624
5.94k
                     it != tracks.end(); ++it )
625
3.77k
                {
626
3.77k
                    _seeker.add_seekpoint( it->first,
627
3.77k
                    SegmentSeeker::Seekpoint( cluster->GetElementPosition(), -1,
628
3.77k
                                              SegmentSeeker::Seekpoint::TrustLevel::QUESTIONABLE ) );
629
3.77k
                }
630
631
                /* stop pre-parsing the stream */
632
2.16k
                break;
633
2.16k
            }
634
2.17k
        }
635
3.68k
        else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
636
46
        {
637
46
            msg_Dbg( &sys.demuxer, "|   + Attachments" );
638
46
            if( i_attachments_position < 0 )
639
33
            {
640
33
                ParseAttachments( ka_ptr );
641
33
                i_attachments_position = el->GetElementPosition();
642
33
            }
643
46
        }
644
3.63k
        else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
645
426
        {
646
426
            msg_Dbg( &sys.demuxer, "|   + Chapters" );
647
426
            if( i_chapters_position < 0 )
648
192
            {
649
192
                ParseChapters( chapters );
650
192
                i_chapters_position = el->GetElementPosition();
651
192
            }
652
426
        }
653
3.20k
        else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
654
480
        {
655
480
            msg_Dbg( &sys.demuxer, "|   + Tags" );
656
480
            if(tags.empty ())
657
417
            {
658
417
                LoadTags( tags_ );
659
417
            }
660
480
        }
661
2.72k
        else if( MKV_IS_ID ( el, EbmlVoid ) )
662
2.72k
            msg_Dbg( &sys.demuxer, "|   + Void" );
663
749
        else
664
749
            msg_Dbg( &sys.demuxer, "|   + Preload Unknown (%s)", EBML_NAME(el) );
665
11.5k
    }
666
667
2.19k
    ComputeTrackPriority();
668
669
2.19k
    b_preloaded = true;
670
671
2.19k
    return true;
672
6.39k
}
673
674
/* Here we try to load elements that were found in Seek Heads, but not yet parsed */
675
bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position )
676
3.10k
{
677
3.10k
    int64_t     i_sav_position = static_cast<int64_t>( es.I_O().getFilePointer() );
678
3.10k
    EbmlElement *el;
679
680
3.10k
    es.I_O().setFilePointer( i_element_position, seek_beginning );
681
3.10k
    el = es.FindNextID( ClassInfos, 0xFFFFFFFFL);
682
683
3.10k
    if( el == nullptr || el->IsDummy() )
684
1.67k
    {
685
1.67k
        msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" );
686
1.67k
        es.I_O().setFilePointer( i_sav_position, seek_beginning );
687
1.67k
        delete el;
688
1.67k
        return false;
689
1.67k
    }
690
691
1.42k
    if( MKV_CHECKED_PTR_DECL ( ksh_ptr, KaxSeekHead, el ) )
692
0
    {
693
        /* Multiple allowed */
694
0
        msg_Dbg( &sys.demuxer, "|   + Seek head" );
695
0
        if( i_seekhead_count < 10 )
696
0
        {
697
0
            if ( i_seekhead_position != i_element_position )
698
0
            {
699
0
                i_seekhead_position = i_element_position;
700
0
                ParseSeekHead( ksh_ptr );
701
0
            }
702
0
        }
703
0
    }
704
1.42k
    else if( MKV_CHECKED_PTR_DECL ( ki_ptr, KaxInfo, el ) ) // FIXME
705
581
    {
706
        /* Multiple allowed, mandatory */
707
581
        msg_Dbg( &sys.demuxer, "|   + Information" );
708
581
        if( i_info_position < 0 )
709
579
        {
710
579
            ParseInfo( ki_ptr );
711
579
            i_info_position = i_element_position;
712
579
        }
713
581
    }
714
844
    else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) // FIXME
715
558
    {
716
        /* Multiple allowed */
717
558
        msg_Dbg( &sys.demuxer, "|   + Tracks" );
718
558
        if( i_tracks_position < 0 )
719
558
            ParseTracks( kt_ptr );
720
558
        if ( tracks.size() == 0 )
721
0
        {
722
0
            msg_Err( &sys.demuxer, "No tracks supported" );
723
0
            delete el;
724
0
            es.I_O().setFilePointer( i_sav_position, seek_beginning );
725
0
            return false;
726
0
        }
727
558
        i_tracks_position = i_element_position;
728
558
    }
729
286
    else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) )
730
59
    {
731
59
        msg_Dbg( &sys.demuxer, "|   + Cues" );
732
59
        if( i_cues_position < 0 )
733
59
        {
734
59
            LoadCues( kc_ptr );
735
59
            i_cues_position = i_element_position;
736
59
        }
737
59
    }
738
227
    else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
739
13
    {
740
13
        msg_Dbg( &sys.demuxer, "|   + Attachments" );
741
13
        if( i_attachments_position < 0 )
742
13
        {
743
13
            ParseAttachments( ka_ptr );
744
13
            i_attachments_position = i_element_position;
745
13
        }
746
13
    }
747
214
    else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
748
169
    {
749
169
        msg_Dbg( &sys.demuxer, "|   + Chapters" );
750
169
        if( i_chapters_position < 0 )
751
169
        {
752
169
            ParseChapters( chapters );
753
169
            i_chapters_position = i_element_position;
754
169
        }
755
169
    }
756
45
    else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
757
45
    {
758
45
        msg_Dbg( &sys.demuxer, "|   + Tags" );
759
45
        if(tags.empty ())
760
45
        {
761
45
            LoadTags( tags_ );
762
45
        }
763
45
    }
764
0
    else
765
0
    {
766
0
        msg_Dbg( &sys.demuxer, "|   + LoadSeekHeadItem Unknown (%s)", EBML_NAME(el) );
767
0
    }
768
1.42k
    delete el;
769
770
1.42k
    es.I_O().setFilePointer( i_sav_position, seek_beginning );
771
1.42k
    return true;
772
1.42k
}
773
774
bool matroska_segment_c::Seek( demux_t &demuxer, vlc_tick_t i_absolute_mk_date, vlc_tick_t i_mk_time_offset, bool b_accurate )
775
2.18k
{
776
2.18k
    SegmentSeeker::tracks_seekpoint_t seekpoints;
777
778
2.18k
    SegmentSeeker::fptr_t i_seek_position = std::numeric_limits<SegmentSeeker::fptr_t>::max();
779
2.18k
    vlc_tick_t i_mk_seek_time = -1;
780
2.18k
    vlc_tick_t i_mk_date = i_absolute_mk_date - i_mk_time_offset;
781
2.18k
    SegmentSeeker::track_ids_t selected_tracks;
782
2.18k
    SegmentSeeker::track_ids_t priority;
783
784
    // reset information for all tracks //
785
786
5.98k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
787
3.80k
    {
788
3.80k
        mkv_track_t &track = *it->second;
789
790
3.80k
        track.i_skip_until_fpos = std::numeric_limits<uint64_t>::max();
791
3.80k
        if( track.i_last_dts != VLC_TICK_INVALID )
792
25
            track.b_discontinuity = true;
793
3.80k
        track.i_last_dts        = VLC_TICK_INVALID;
794
795
3.80k
        bool selected;
796
3.80k
        if (track.p_es == NULL)
797
39
            selected = false;
798
3.76k
        else
799
3.76k
            es_out_Control( demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &selected );
800
3.80k
        if ( selected )
801
3.76k
            selected_tracks.push_back( track.i_number );
802
3.80k
    }
803
804
2.18k
    if ( selected_tracks.empty() )
805
16
    {
806
16
        selected_tracks = priority_tracks;
807
16
        priority = priority_tracks;
808
16
    }
809
2.16k
    else
810
2.16k
    {
811
2.16k
        std::set_intersection(priority_tracks.begin(),priority_tracks.end(),
812
2.16k
                              selected_tracks.begin(),selected_tracks.end(),
813
2.16k
                              std::back_inserter(priority));
814
2.16k
        if (priority.empty()) // no video selected ?
815
16
            priority = selected_tracks;
816
2.16k
    }
817
818
    // find appropriate seekpoints //
819
820
2.18k
    try {
821
2.18k
        seekpoints = _seeker.get_seekpoints( *this, i_mk_date, priority, selected_tracks );
822
2.18k
    }
823
2.18k
    catch( std::exception const& e )
824
2.18k
    {
825
0
        msg_Err( &sys.demuxer, "error during seek: \"%s\", aborting!", e.what() );
826
0
        return false;
827
0
    }
828
829
    // initialize seek information in order to set up playback //
830
831
5.94k
    for( SegmentSeeker::tracks_seekpoint_t::const_iterator it = seekpoints.begin(); it != seekpoints.end(); ++it )
832
3.75k
    {
833
3.75k
        tracks_map_t::iterator trackit = tracks.find( it->first );
834
3.75k
        if ( trackit == tracks.end() )
835
0
            continue; // there were blocks with unknown tracks
836
837
3.75k
        if( i_seek_position > it->second.fpos )
838
2.42k
        {
839
2.42k
            i_seek_position = it->second.fpos;
840
2.42k
            i_mk_seek_time  = it->second.pts;
841
2.42k
        }
842
843
        // blocks that will be not be read until this fpos
844
3.75k
        if ( b_accurate )
845
3.75k
            trackit->second->i_skip_until_fpos = it->second.fpos;
846
0
        else
847
0
            trackit->second->i_skip_until_fpos = std::numeric_limits<uint64_t>::max();
848
3.75k
        if (it->second.pts != -1)
849
1.24k
            trackit->second->i_last_dts        = it->second.pts + i_mk_time_offset;
850
851
3.75k
        msg_Dbg( &sys.demuxer, "seek: preroll{ track: %u, pts: %" PRId64 ", fpos: %" PRIu64 " skip: %" PRIu64 "} ",
852
3.75k
          it->first, it->second.pts, it->second.fpos, trackit->second->i_skip_until_fpos );
853
3.75k
    }
854
855
2.18k
    if ( i_seek_position == std::numeric_limits<SegmentSeeker::fptr_t>::max() )
856
14
        return false;
857
858
    // propagate seek information //
859
860
2.16k
    sys.i_pcr           = VLC_TICK_INVALID;
861
2.16k
    sys.i_pts           = VLC_TICK_0 + i_mk_seek_time + i_mk_time_offset;
862
2.16k
    if (b_accurate)
863
2.16k
        sys.i_start_pts = VLC_TICK_0 + i_absolute_mk_date;
864
0
    else
865
0
        sys.i_start_pts = sys.i_pts;
866
867
    // make the jump //
868
869
2.16k
    _seeker.mkv_jump_to( *this, i_seek_position );
870
871
    // debug diagnostics //
872
873
2.16k
    msg_Dbg( &sys.demuxer, "seek: preroll{ req: %" PRId64 ", start-pts: %" PRId64 ", start-fpos: %" PRIu64 "} ",
874
2.16k
      sys.i_start_pts, sys.i_pts, i_seek_position );
875
876
    // blocks that will be read and decoded but discarded until this pts
877
2.16k
    es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts );
878
2.16k
    return true;
879
2.18k
}
880
881
882
mkv_track_t * matroska_segment_c::FindTrackByBlock(
883
                                             const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
884
259k
{
885
259k
    tracks_map_t::iterator track_it;
886
887
259k
    if (p_block != NULL)
888
145k
        track_it = tracks.find( p_block->TrackNum() );
889
114k
    else if( p_simpleblock != NULL)
890
114k
        track_it = tracks.find( p_simpleblock->TrackNum() );
891
0
    else
892
0
        track_it = tracks.end();
893
894
259k
    if (track_it == tracks.end())
895
6.63k
        return NULL;
896
897
253k
    return track_it->second.get();
898
259k
}
899
900
void matroska_segment_c::ComputeTrackPriority()
901
2.19k
{
902
2.19k
    bool b_has_default_video = false;
903
2.19k
    bool b_has_default_audio = false;
904
    /* check for default */
905
6.07k
    for( tracks_map_t::const_iterator it = tracks.begin(); it != tracks.end();
906
3.88k
         ++it )
907
3.88k
    {
908
3.88k
        mkv_track_t &track = *it->second;
909
910
3.88k
        bool flag = track.b_enabled && ( track.b_default || track.b_forced );
911
912
3.88k
        switch( track.fmt.i_cat )
913
3.88k
        {
914
1.91k
            case VIDEO_ES: b_has_default_video |= flag; break;
915
1.38k
            case AUDIO_ES: b_has_default_audio |= flag; break;
916
582
            default: break; // ignore
917
3.88k
        }
918
3.88k
    }
919
920
6.07k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
921
3.88k
    {
922
3.88k
        tracks_map_t::key_type track_id = it->first;
923
3.88k
        mkv_track_t          & track    = *it->second;
924
925
3.88k
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
926
38
        {
927
38
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
928
38
            track.p_es = NULL;
929
38
            continue;
930
38
        }
931
3.84k
        else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) )
932
606
        {
933
606
            track.b_default = true;
934
606
            b_has_default_video = true;
935
606
        }
936
3.23k
        else if( unlikely( !b_has_default_audio &&  track.fmt.i_cat == AUDIO_ES ) )
937
24
        {
938
24
            track.b_default = true;
939
24
            b_has_default_audio = true;
940
24
        }
941
3.84k
        if( unlikely( !track.b_enabled ) )
942
0
            track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
943
3.84k
        else if( track.b_forced )
944
0
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
945
3.84k
        else if( track.b_default )
946
3.30k
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
947
534
        else
948
534
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
949
950
        /* Avoid multivideo tracks when unnecessary */
951
3.84k
        if( track.fmt.i_cat == VIDEO_ES )
952
1.89k
            track.fmt.i_priority--;
953
3.84k
    }
954
955
    // find track(s) with highest priority //
956
2.19k
    {
957
2.19k
        int   score = -1;
958
2.19k
        int es_type = -1;
959
960
6.07k
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
961
3.88k
        {
962
3.88k
            int track_score = -1;
963
964
3.88k
            switch( it->second->fmt.i_cat )
965
3.88k
            {
966
1.91k
                case VIDEO_ES: ++track_score;
967
                /* fallthrough */
968
3.29k
                case AUDIO_ES: ++track_score;
969
                /* fallthrough */
970
3.86k
                case   SPU_ES: ++track_score;
971
                /* fallthrough */
972
3.88k
                default:
973
3.88k
                  if( score < track_score )
974
2.20k
                  {
975
2.20k
                      es_type = it->second->fmt.i_cat;
976
2.20k
                      score   = track_score;
977
2.20k
                  }
978
3.88k
            }
979
3.88k
        }
980
981
6.07k
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
982
3.88k
        {
983
3.88k
            if( it->second->fmt.i_cat == es_type )
984
2.19k
                priority_tracks.push_back( it->first );
985
3.88k
        }
986
2.19k
    }
987
2.19k
}
988
989
bool matroska_segment_c::EnsureDuration(KaxCluster & fromCluster)
990
2.17k
{
991
2.17k
    if ( i_duration > 0 )
992
617
        return true;
993
994
1.56k
    i_duration = -1;
995
996
1.56k
    if( !sys.b_fastseekable )
997
0
    {
998
0
        msg_Warn( &sys.demuxer, "could not look for the segment duration" );
999
0
        return true;
1000
0
    }
1001
1002
1.56k
    uint64_t i_current_position = es.I_O().getFilePointer();
1003
1.56k
    uint64_t i_last_cluster_pos = fromCluster.GetElementPosition();
1004
1005
    // find the last Cluster from the Cues
1006
1007
1.56k
    if ( b_cues && _seeker._cluster_positions.size() )
1008
25
        i_last_cluster_pos = *_seeker._cluster_positions.rbegin();
1009
1.53k
    else if( !fromCluster.IsFiniteSize() )
1010
1.13k
    {
1011
        // make sure our first Cluster has a timestamp
1012
1.13k
        return ParseCluster( &fromCluster, false, SCOPE_PARTIAL_DATA );
1013
1.13k
    }
1014
1015
422
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1016
1017
422
    EbmlParser eparser ( &es, segment, &sys.demuxer );
1018
1019
    // locate the definitely last cluster in the stream
1020
1021
7.70k
    while( EbmlElement* el = eparser.Get() )
1022
7.32k
    {
1023
7.32k
        if( !el->IsFiniteSize() && el->GetElementPosition() != i_last_cluster_pos )
1024
24
        {
1025
24
            es.I_O().setFilePointer( i_current_position, seek_beginning );
1026
24
            return true;
1027
24
        }
1028
1029
7.29k
        if( MKV_IS_ID( el, KaxCluster ) )
1030
5.30k
        {
1031
5.30k
            i_last_cluster_pos = el->GetElementPosition();
1032
5.30k
            if ( i_last_cluster_pos == fromCluster.GetElementPosition() )
1033
399
            {
1034
                // make sure our first Cluster has a timestamp
1035
399
                if (!ParseCluster( &fromCluster, true, SCOPE_PARTIAL_DATA ))
1036
9
                    return false;
1037
399
            }
1038
5.30k
        }
1039
7.29k
    }
1040
1041
    // find the last timecode in the Cluster
1042
1043
389
    eparser.Reset( &sys.demuxer );
1044
389
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1045
1046
389
    EbmlElement* el = eparser.Get();
1047
389
    MKV_CHECKED_PTR_DECL( p_last_cluster, KaxCluster, el );
1048
1049
389
    if( p_last_cluster &&
1050
366
        ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA ) )
1051
361
    {
1052
        // use the last block + duration
1053
361
        uint64_t i_last_timecode = p_last_cluster->GlobalTimestamp();
1054
361
        for (auto l : *p_last_cluster)
1055
7.68k
        {
1056
7.68k
            if( MKV_CHECKED_PTR_DECL ( simpleblock, KaxSimpleBlock, l ) )
1057
2.37k
            {
1058
2.37k
                simpleblock->SetParent( *p_last_cluster );
1059
2.37k
                i_last_timecode = std::max(i_last_timecode, simpleblock->GlobalTimestamp());
1060
2.37k
            }
1061
5.30k
            else if( MKV_CHECKED_PTR_DECL_CONST ( group, KaxBlockGroup, l ) )
1062
426
            {
1063
426
                uint64_t i_group_timecode = 0;
1064
426
                for (auto g : *group)
1065
1.03k
                {
1066
1.03k
                    if( MKV_CHECKED_PTR_DECL ( block, KaxBlock, g ) )
1067
393
                    {
1068
393
                        block->SetParent( *p_last_cluster );
1069
393
                        i_group_timecode += block->GlobalTimestamp();
1070
393
                    }
1071
639
                    else if( MKV_CHECKED_PTR_DECL_CONST ( kbd_ptr, KaxBlockDuration, g ) )
1072
9
                    {
1073
9
                        i_group_timecode += static_cast<uint64_t>( *kbd_ptr );
1074
9
                    }
1075
1.03k
                }
1076
426
                i_last_timecode = std::max(i_last_timecode, i_group_timecode);
1077
426
            }
1078
7.68k
        }
1079
1080
361
        i_duration = VLC_TICK_FROM_NS( i_last_timecode - fromCluster.GlobalTimestamp() );
1081
361
        msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, SEC_FROM_VLC_TICK(i_duration) );
1082
361
    }
1083
1084
    // get back to the reading position we were at before looking for a duration
1085
389
    es.I_O().setFilePointer( i_current_position, seek_beginning );
1086
389
    return true;
1087
422
}
1088
1089
bool matroska_segment_c::ESCreate()
1090
2.15k
{
1091
    /* add all es */
1092
2.15k
    msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) );
1093
1094
2.15k
    mkv_track_t *default_tracks[ES_CATEGORY_COUNT] = {};
1095
5.92k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1096
3.76k
    {
1097
3.76k
        tracks_map_t::key_type   track_id = it->first;
1098
3.76k
        mkv_track_t            & track    = *it->second;
1099
1100
3.76k
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
1101
38
        {
1102
38
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
1103
38
            track.p_es = NULL;
1104
38
            continue;
1105
38
        }
1106
3.73k
        track.fmt.i_id = static_cast<int>( track_id );
1107
1108
3.73k
        if( !track.p_es )
1109
3.73k
        {
1110
3.73k
            track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
1111
1112
3.73k
            if( track.p_es &&
1113
3.73k
                !sys.ev.AddTrack( track ) )
1114
1.87k
            {
1115
1.87k
                msg_Warn( &sys.demuxer, "Could not register events, interactive menus will not work");
1116
1.87k
            }
1117
3.73k
        }
1118
1119
        /* Turn on a subtitles track if it has been flagged as default -
1120
         * but only do this if no subtitles track has already been engaged,
1121
         * either by an earlier 'default track' (??) or by default
1122
         * language choice behaviour.
1123
         */
1124
3.73k
        if( track.b_default || track.b_forced )
1125
3.25k
        {
1126
3.25k
            mkv_track_t *&default_track = default_tracks[track.fmt.i_cat];
1127
3.25k
            if( !default_track || track.b_default )
1128
3.25k
                default_track = &track;
1129
3.25k
        }
1130
3.73k
    }
1131
1132
2.15k
    for( mkv_track_t *track : default_tracks )
1133
10.7k
    {
1134
10.7k
        if( track )
1135
3.25k
            es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track->p_es );
1136
10.7k
    }
1137
1138
2.15k
    return true;
1139
2.15k
}
1140
1141
void matroska_segment_c::ESDestroy( )
1142
2.15k
{
1143
2.15k
    sys.ev.AbortThread();
1144
1145
5.92k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1146
3.76k
    {
1147
3.76k
        mkv_track_t & track = *it->second;
1148
1149
3.76k
        if( track.p_es != NULL )
1150
3.73k
        {
1151
3.73k
            es_out_Del( sys.demuxer.out, track.p_es );
1152
3.73k
            sys.ev.DelTrack( track );
1153
3.73k
            track.p_es = NULL;
1154
3.73k
        }
1155
3.76k
    }
1156
2.15k
}
1157
1158
int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_simpleblock,
1159
                                  KaxBlockAdditions * & pp_additions,
1160
                                  bool *pb_key_picture, bool *pb_discardable_picture,
1161
                                  int64_t *pi_duration )
1162
71.7k
{
1163
71.7k
    pp_simpleblock = NULL;
1164
71.7k
    pp_block = NULL;
1165
71.7k
    pp_additions = NULL;
1166
1167
71.7k
    *pb_key_picture         = true;
1168
71.7k
    *pb_discardable_picture = false;
1169
71.7k
    *pi_duration = 0;
1170
1171
71.7k
    struct BlockPayload {
1172
71.7k
        matroska_segment_c * const obj;
1173
71.7k
        EbmlParser         * const ep;
1174
71.7k
        demux_t            * const p_demuxer;
1175
71.7k
        KaxBlock          *& block;
1176
71.7k
        KaxSimpleBlock    *& simpleblock;
1177
71.7k
        KaxBlockAdditions *& additions;
1178
1179
71.7k
        int64_t            & i_duration;
1180
71.7k
        bool               & b_key_picture;
1181
71.7k
        bool               & b_discardable_picture;
1182
71.7k
        bool                 b_cluster_timecode;
1183
1184
71.7k
    } payload = {
1185
71.7k
        this, &ep, &sys.demuxer, pp_block, pp_simpleblock, pp_additions,
1186
71.7k
        *pi_duration, *pb_key_picture, *pb_discardable_picture, true
1187
71.7k
    };
1188
1189
71.7k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l1, BlockPayload )
1190
71.7k
    {
1191
71.7k
        MKV_SWITCH_INIT();
1192
1193
71.7k
        E_CASE( KaxCluster, kcluster )
1194
71.7k
        {
1195
27.3k
            vars.obj->cluster = &kcluster;
1196
27.3k
            vars.b_cluster_timecode = false;
1197
27.3k
            vars.ep->Down ();
1198
27.3k
        }
1199
71.7k
        E_CASE( KaxCues, kcue )
1200
71.7k
        {
1201
99
            VLC_UNUSED( kcue );
1202
99
            msg_Warn( vars.p_demuxer, "find KaxCues FIXME" );
1203
99
        }
1204
71.7k
        E_CASE_DEFAULT(element)
1205
71.7k
        {
1206
28.3k
            msg_Dbg( vars.p_demuxer, "Unknown (%s)", EBML_NAME(&element) );
1207
28.3k
        }
1208
71.7k
    };
1209
1210
71.7k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l2, BlockPayload )
1211
71.7k
    {
1212
71.7k
        MKV_SWITCH_INIT();
1213
1214
71.7k
        E_CASE( KaxClusterTimestamp, ktimecode )
1215
71.7k
        {
1216
43.9k
            ktimecode.ReadData( vars.obj->es.I_O(), SCOPE_ALL_DATA );
1217
43.9k
            vars.obj->cluster->InitTimestamp( static_cast<uint64_t>( ktimecode ), vars.obj->i_timescale );
1218
43.9k
            vars.obj->_seeker.add_cluster( vars.obj->cluster );
1219
43.9k
            vars.b_cluster_timecode = true;
1220
43.9k
        }
1221
71.7k
        E_CASE( KaxClusterSilentTracks, ksilent )
1222
71.7k
        {
1223
2
            vars.ep->Down ();
1224
1225
2
            VLC_UNUSED( ksilent );
1226
2
        }
1227
71.7k
        E_CASE( KaxBlockGroup, kbgroup )
1228
71.7k
        {
1229
44.0k
            if( vars.b_cluster_timecode == false )
1230
273
            {
1231
273
                msg_Warn( vars.p_demuxer, "ignoring KaxBlockGroup prior to mandatory Timecode" );
1232
273
                return;
1233
273
            }
1234
1235
43.7k
            vars.obj->i_block_pos = kbgroup.GetElementPosition();
1236
43.7k
            vars.ep->Down ();
1237
43.7k
        }
1238
71.7k
        E_CASE( KaxSimpleBlock, ksblock )
1239
71.7k
        {
1240
36.8k
            if( vars.b_cluster_timecode == false )
1241
18
            {
1242
18
                msg_Warn( vars.p_demuxer, "ignoring SimpleBlock prior to mandatory Timecode" );
1243
18
                return;
1244
18
            }
1245
1246
36.8k
            filepos_t read = 0;
1247
36.8k
            try {
1248
36.8k
                read = ksblock.ReadData( vars.obj->es.I_O() );
1249
36.8k
            } catch(...) {
1250
0
            }
1251
36.8k
            if (read == 0 && ksblock.GetSize() != 0) {
1252
2.14k
                msg_Err( vars.p_demuxer,"Error while reading %s",  EBML_NAME(&ksblock) );
1253
2.14k
                ksblock.ReleaseFrames();
1254
2.14k
                return;
1255
2.14k
            }
1256
34.7k
            vars.simpleblock = &ksblock;
1257
34.7k
            vars.simpleblock->SetParent( *vars.obj->cluster );
1258
1259
34.7k
            if( ksblock.IsKeyframe() )
1260
16.8k
            {
1261
16.8k
                bool const b_valid_track = vars.obj->FindTrackByBlock( NULL, &ksblock ) != NULL;
1262
16.8k
                if (b_valid_track)
1263
15.4k
                    vars.obj->_seeker.add_seekpoint( ksblock.TrackNum(),
1264
15.4k
                        SegmentSeeker::Seekpoint( ksblock.GetElementPosition(), VLC_TICK_FROM_NS(ksblock.GlobalTimestamp()) ) );
1265
16.8k
            }
1266
34.7k
        }
1267
71.7k
    };
1268
1269
71.7k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l3, BlockPayload )
1270
71.7k
    {
1271
71.7k
        MKV_SWITCH_INIT();
1272
1273
71.7k
        E_CASE( KaxBlock, kblock )
1274
71.7k
        {
1275
38.7k
            filepos_t read = 0;
1276
38.7k
            try {
1277
38.7k
                read = kblock.ReadData( vars.obj->es.I_O() );
1278
38.7k
            } catch(...) {
1279
0
            }
1280
38.7k
            if (unlikely(read == 0) && kblock.GetSize() != 0) {
1281
130
                msg_Err( vars.p_demuxer,"Error while reading %s",  EBML_NAME(&kblock) );
1282
130
                kblock.ReleaseFrames();
1283
130
                return;
1284
130
            }
1285
38.5k
            vars.block = &kblock;
1286
38.5k
            vars.block->SetParent( *vars.obj->cluster );
1287
1288
38.5k
            const mkv_track_t *p_track = vars.obj->FindTrackByBlock( &kblock, NULL );
1289
38.5k
            if( p_track != NULL && p_track->fmt.i_cat == SPU_ES )
1290
163
            {
1291
163
                vars.obj->_seeker.add_seekpoint( kblock.TrackNum(),
1292
163
                    SegmentSeeker::Seekpoint( kblock.GetElementPosition(), VLC_TICK_FROM_NS(kblock.GlobalTimestamp()) ) );
1293
163
            }
1294
1295
38.5k
            vars.ep->Keep ();
1296
38.5k
        }
1297
71.7k
        E_CASE( KaxBlockAdditions, kadditions )
1298
71.7k
        {
1299
2.27k
            if ( vars.obj->ReadMaster( kadditions ) )
1300
2.27k
            {
1301
2.27k
                vars.additions = &kadditions;
1302
2.27k
                vars.ep->Keep ();
1303
2.27k
            }
1304
2.27k
        }
1305
71.7k
        E_CASE( KaxBlockDuration, kduration )
1306
71.7k
        {
1307
6.04k
            kduration.ReadData( vars.obj->es.I_O() );
1308
6.04k
            vars.i_duration = static_cast<uint64_t>( kduration );
1309
6.04k
        }
1310
71.7k
        E_CASE( KaxReferenceBlock, kreference )
1311
71.7k
        {
1312
12.1k
           kreference.ReadData( vars.obj->es.I_O() );
1313
1314
12.1k
           if( vars.b_key_picture )
1315
11.7k
               vars.b_key_picture = false;
1316
347
           else if( static_cast<int64_t>( kreference ) )
1317
347
               vars.b_discardable_picture = true;
1318
12.1k
        }
1319
71.7k
        E_CASE( KaxClusterSilentTrackNumber, kstrackn )
1320
71.7k
        {
1321
0
            VLC_UNUSED( kstrackn );
1322
0
            VLC_UNUSED( vars );
1323
0
        }
1324
71.7k
#if LIBMATROSKA_VERSION >= 0x010401
1325
71.7k
        E_CASE( KaxDiscardPadding, kdiscardp )
1326
71.7k
        {
1327
0
            kdiscardp.ReadData( vars.obj->es.I_O() );
1328
0
            int64_t i_duration = static_cast<int64_t>( kdiscardp );
1329
1330
0
            if( vars.i_duration < i_duration )
1331
0
                vars.i_duration = 0;
1332
0
            else
1333
0
                vars.i_duration -= i_duration;
1334
0
        }
1335
71.7k
#endif
1336
71.7k
        E_CASE_DEFAULT( element )
1337
71.7k
        {
1338
117
            VLC_UNUSED(element);
1339
1340
117
            msg_Warn( vars.p_demuxer, "unknown element at { fpos: %" PRId64 ", '%s' }",
1341
117
              element.GetElementPosition(), EBML_NAME( &element ) );
1342
117
        }
1343
71.7k
    };
1344
1345
71.7k
    static EbmlTypeDispatcher const * const dispatchers[] = {
1346
71.7k
        &BlockGetHandler_l1::Dispatcher(),
1347
71.7k
        &BlockGetHandler_l2::Dispatcher(),
1348
71.7k
        &BlockGetHandler_l3::Dispatcher()
1349
71.7k
    };
1350
1351
71.7k
    for( ;; )
1352
390k
    {
1353
390k
        EbmlElement *el = NULL;
1354
390k
        int         i_level;
1355
1356
390k
        if( pp_simpleblock != NULL || ((el = ep.Get()) == NULL && pp_block != NULL) )
1357
73.2k
        {
1358
            /* Check blocks validity to protect against broken files */
1359
73.2k
            const mkv_track_t *p_track = FindTrackByBlock( pp_block , pp_simpleblock );
1360
73.2k
            if( p_track == NULL )
1361
3.83k
            {
1362
3.83k
                ep.Unkeep();
1363
3.83k
                pp_simpleblock = NULL;
1364
3.83k
                pp_block = NULL;
1365
3.83k
                continue;
1366
3.83k
            }
1367
69.4k
            if( pp_simpleblock != NULL )
1368
32.2k
            {
1369
32.2k
                *pb_key_picture         = pp_simpleblock->IsKeyframe();
1370
32.2k
                *pb_discardable_picture = pp_simpleblock->IsDiscardable();
1371
32.2k
            }
1372
            /* We have block group let's check if the picture is a keyframe */
1373
37.1k
            else if( *pb_key_picture )
1374
25.4k
            {
1375
25.4k
                if( p_track->fmt.i_codec == VLC_CODEC_THEORA )
1376
1.31k
                {
1377
1.31k
                    DataBuffer *    p_data = &pp_block->GetBuffer(0);
1378
1.31k
                    const uint8_t * p_buff = p_data->Buffer();
1379
                    /* if the second bit of a Theora frame is 1
1380
                       it's not a keyframe */
1381
1.31k
                    if( p_data->Size() && p_buff )
1382
1.31k
                    {
1383
1.31k
                        if( p_buff[0] & 0x40 )
1384
1.02k
                            *pb_key_picture = false;
1385
1.31k
                    }
1386
4
                    else
1387
4
                        *pb_key_picture = false;
1388
1.31k
                }
1389
25.4k
            }
1390
1391
69.4k
            return VLC_SUCCESS;
1392
73.2k
        }
1393
1394
317k
        i_level = ep.GetLevel();
1395
1396
317k
        if( el == NULL )
1397
74.0k
        {
1398
74.0k
            if( i_level > 1 )
1399
71.7k
            {
1400
71.7k
                ep.Up();
1401
71.7k
                continue;
1402
71.7k
            }
1403
2.26k
            msg_Warn( &sys.demuxer, "EOF" );
1404
2.26k
            return VLC_EGENERIC;
1405
74.0k
        }
1406
1407
        /* Verify that we are still inside our cluster
1408
         * It can happens with broken files and when seeking
1409
         * without index */
1410
243k
        if( i_level > 1 )
1411
187k
        {
1412
187k
            if( cluster && !ep.IsTopPresent( cluster ) )
1413
0
            {
1414
0
                msg_Warn( &sys.demuxer, "Unexpected escape from current cluster" );
1415
0
                cluster = NULL;
1416
0
            }
1417
187k
            if( !cluster )
1418
0
                continue;
1419
187k
        }
1420
1421
        /* do parsing */
1422
1423
243k
        try {
1424
243k
            switch( i_level )
1425
243k
            {
1426
128k
                case 2:
1427
                /* fallthrough */
1428
187k
                case 3:
1429
187k
                    if( unlikely( !el->ValidateSize() || ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) )
1430
0
                    {
1431
0
                        msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1432
0
                        ep.Up();
1433
1434
0
                        if ( i_level == 2 )
1435
0
                            break;
1436
1437
0
                        ep.Unkeep();
1438
0
                        pp_simpleblock = NULL;
1439
0
                        pp_block = NULL;
1440
1441
0
                        break;
1442
0
                    }
1443
                    /* fallthrough */
1444
243k
                case 1:
1445
243k
                    {
1446
243k
                        EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1];
1447
243k
                        dispatcher->send( el, &payload );
1448
243k
                    }
1449
243k
                    break;
1450
1451
0
                default:
1452
0
                    msg_Err( &sys.demuxer, "invalid level = %d", i_level );
1453
0
                    return VLC_EGENERIC;
1454
243k
            }
1455
243k
        }
1456
243k
        catch (int ret_code)
1457
243k
        {
1458
0
            return ret_code;
1459
0
        }
1460
243k
        catch (...)
1461
243k
        {
1462
0
            msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1463
0
            ep.Up();
1464
0
            ep.Unkeep();
1465
0
            pp_simpleblock = NULL;
1466
            pp_block = NULL;
1467
0
        }
1468
243k
    }
1469
71.7k
}
1470
1471
} // namespace