Coverage Report

Created: 2026-05-30 08:50

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