Coverage Report

Created: 2026-10-17 07:46

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.10k
    :segment(p_seg)
40
2.10k
    ,es(estream)
41
2.10k
    ,i_timescale(MKVD_TIMECODESCALE)
42
2.10k
    ,i_duration(-1)
43
2.10k
    ,i_mk_start_time(0)
44
2.10k
    ,i_seekhead_count(0)
45
2.10k
    ,i_seekhead_position(-1)
46
2.10k
    ,i_cues_position(-1)
47
2.10k
    ,i_tracks_position(-1)
48
2.10k
    ,i_info_position(-1)
49
2.10k
    ,i_chapters_position(-1)
50
2.10k
    ,i_attachments_position(-1)
51
2.10k
    ,cluster(NULL)
52
2.10k
    ,i_block_pos(0)
53
2.10k
    ,p_segment_uid(NULL)
54
2.10k
    ,p_prev_segment_uid(NULL)
55
2.10k
    ,p_next_segment_uid(NULL)
56
2.10k
    ,b_cues(false)
57
2.10k
    ,psz_muxing_application(NULL)
58
2.10k
    ,psz_writing_application(NULL)
59
2.10k
    ,psz_title(NULL)
60
2.10k
    ,i_default_edition(0)
61
2.10k
    ,sys(demuxer)
62
2.10k
    ,ep( EbmlParser(&estream, p_seg, &demuxer.demuxer ))
63
2.10k
    ,b_preloaded(false)
64
2.10k
    ,b_ref_external_segments(false)
65
2.10k
{
66
2.10k
}
67
68
matroska_segment_c::~matroska_segment_c()
69
2.10k
{
70
2.10k
    free( psz_writing_application );
71
2.10k
    free( psz_muxing_application );
72
2.10k
    free( psz_title );
73
74
2.10k
    delete segment;
75
2.10k
    delete p_segment_uid;
76
2.10k
    delete p_prev_segment_uid;
77
2.10k
    delete p_next_segment_uid;
78
79
2.10k
    vlc_delete_all( stored_editions );
80
2.10k
    vlc_delete_all( translations );
81
2.10k
    vlc_delete_all( families );
82
2.10k
}
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
127
{
94
127
    EbmlElement *el;
95
96
127
    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
127
    EbmlParser eparser (&es, cues, &sys.demuxer );
103
2.91k
    while( ( el = eparser.Get() ) != NULL )
104
2.79k
    {
105
2.79k
        if( MKV_IS_ID( el, KaxCuePoint ) )
106
2.68k
        {
107
2.68k
            uint64_t cue_position = -1;
108
2.68k
            vlc_tick_t  cue_mk_time = -1;
109
110
2.68k
            unsigned int track_id = 0;
111
2.68k
            bool b_invalid_cue = false;
112
113
2.68k
            eparser.Down();
114
7.97k
            while( ( el = eparser.Get() ) != NULL )
115
5.28k
            {
116
5.28k
                if ( MKV_CHECKED_PTR_DECL( cuetime, KaxCueTime, el ) )
117
2.66k
                {
118
2.66k
                    try
119
2.66k
                    {
120
2.66k
                        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.66k
                        cuetime->ReadData( es.I_O() );
127
2.66k
                    }
128
2.66k
                    catch(...)
129
2.66k
                    {
130
0
                        msg_Err( &sys.demuxer, "Error while reading CueTime" );
131
0
                        b_invalid_cue = true;
132
0
                        break;
133
0
                    }
134
2.66k
                    cue_mk_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( *cuetime ) * i_timescale);
135
2.66k
                }
136
2.61k
                else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
137
2.61k
                {
138
2.61k
                    eparser.Down();
139
2.61k
                    try
140
2.61k
                    {
141
8.06k
                        while( ( el = eparser.Get() ) != NULL )
142
5.44k
                        {
143
5.44k
                            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.44k
                            if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) )
152
2.61k
                            {
153
2.61k
                                kct_ptr->ReadData( es.I_O() );
154
2.61k
                                track_id = static_cast<uint16_t>( *kct_ptr );
155
2.61k
                            }
156
2.83k
                            else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) )
157
2.60k
                            {
158
2.60k
                                kccp_ptr->ReadData( es.I_O() );
159
2.60k
                                cue_position = segment->GetGlobalPosition( static_cast<uint64_t>( *kccp_ptr ) );
160
161
2.60k
                                _seeker.add_cluster_position( cue_position );
162
2.60k
                            }
163
233
                            else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) )
164
0
                            {
165
0
                                VLC_UNUSED( kcbn_ptr );
166
0
                            }
167
233
#if LIBMATROSKA_VERSION >= 0x010401
168
233
                            else if( MKV_CHECKED_PTR_DECL( cuerelative, KaxCueRelativePosition, el ) )
169
225
                            {
170
225
                                VLC_UNUSED( cuerelative );
171
225
                            }
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.44k
                        }
190
2.61k
                    }
191
2.61k
                    catch(...)
192
2.61k
                    {
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.61k
                    eparser.Up();
199
2.61k
                }
200
1
                else
201
1
                {
202
1
                    msg_Dbg( &sys.demuxer, "     * Unknown (%s)", EBML_NAME(el) );
203
1
                }
204
5.28k
            }
205
2.68k
            eparser.Up();
206
207
2.68k
            if( track_id != 0 && cue_mk_time != -1 && cue_position != static_cast<uint64_t>( -1 ) ) {
208
209
2.59k
                SegmentSeeker::Seekpoint::TrustLevel level = SegmentSeeker::Seekpoint::DISABLED;
210
211
2.59k
                if( ! b_invalid_cue && tracks.find( track_id ) != tracks.end() )
212
2.45k
                {
213
2.45k
                    level = sys.trust_cues ?
214
0
                            SegmentSeeker::Seekpoint::TRUSTED :
215
2.45k
                            SegmentSeeker::Seekpoint::QUESTIONABLE;
216
2.45k
                }
217
218
2.59k
                _seeker.add_seekpoint( track_id,
219
2.59k
                    SegmentSeeker::Seekpoint( cue_position, cue_mk_time, level ) );
220
2.59k
            }
221
2.68k
        }
222
103
        else
223
103
        {
224
103
            msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) );
225
103
        }
226
2.79k
    }
227
127
    b_cues = true;
228
127
    msg_Dbg( &sys.demuxer, "|   - loading cues done." );
229
127
}
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
386
{
270
386
    msg_Dbg( &sys.demuxer, "|   + Simple Tag ");
271
386
    struct SimpleTagHandlerPayload
272
386
    {
273
386
        matroska_segment_c * const obj;
274
386
        EbmlParser         * const ep;
275
386
        demux_sys_t        & sys;
276
386
        SimpleTag          & out;
277
386
        int                target_type;
278
386
    } payload = { this, &ep, sys, *pout_simple, 50 };
279
386
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, SimpleTagHandler, SimpleTagHandlerPayload )
280
386
    {
281
386
        MKV_SWITCH_INIT();
282
386
        E_CASE( KaxTagName, entry )
283
386
        {
284
317
            vars.out.tag_name = UTFstring( entry ).GetUTF8().c_str();
285
317
        }
286
386
        E_CASE( KaxTagString, entry )
287
386
        {
288
315
            vars.out.value = UTFstring( entry ).GetUTF8().c_str();
289
315
        }
290
386
        E_CASE( KaxTagLangue, entry )
291
386
        {
292
14
            vars.out.lang = entry.GetValue();
293
14
        }
294
386
        E_CASE( KaxTagDefault, unused )
295
386
        {
296
0
            VLC_UNUSED(unused);
297
0
            VLC_UNUSED(vars);
298
0
        }
299
386
        E_CASE( KaxTagSimple, simple )
300
386
        {
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
386
    };
308
386
    SimpleTagHandler::Dispatcher().iterate( tag->begin(), tag->end(), &payload );
309
310
386
    if( pout_simple->tag_name.empty() )
311
69
    {
312
69
        msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found.");
313
69
        return false;
314
69
    }
315
317
    if( !sys.meta )
316
102
        sys.meta = vlc_meta_New();
317
5.78k
    for( int i = 0; metadata_map[i].key; i++ )
318
5.66k
    {
319
5.66k
        if( pout_simple->tag_name == metadata_map[i].key &&
320
268
            (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) )
321
198
        {
322
198
            vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () );
323
198
            msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
324
198
            goto done;
325
198
        }
326
5.66k
    }
327
119
    msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
328
119
    vlc_meta_SetExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
329
317
done:
330
317
    return true;
331
119
}
332
333
void matroska_segment_c::LoadTags( KaxTags *tags_ )
334
1.23k
{
335
1.23k
    if ( !ReadMaster( *tags_ ) )
336
436
        return;
337
338
796
    struct TagsHandlerPayload
339
796
    {
340
796
        matroska_segment_c * const obj;
341
796
        EbmlParser         * const ep;
342
796
        demux_sys_t        & sys;
343
796
        int                target_type;
344
796
    } payload = { this, &ep, sys, 50 };
345
796
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxTagsHandler, TagsHandlerPayload )
346
796
    {
347
796
        MKV_SWITCH_INIT();
348
796
        E_CASE( KaxTag, entry )
349
796
        {
350
213
            msg_Dbg( &vars.sys.demuxer, "+ Tag" );
351
213
            Tag tag;
352
213
            struct TagHandlerPayload
353
213
            {
354
213
                matroska_segment_c * const obj;
355
213
                EbmlParser         * const ep;
356
213
                demux_sys_t        & sys;
357
213
                Tag                & tag;
358
213
                int                target_type;
359
213
            } payload = { vars.obj, vars.ep, vars.sys, tag, 50 };
360
213
            MKV_SWITCH_CREATE( EbmlTypeDispatcher, TagHandler, TagHandlerPayload )
361
213
            {
362
213
                MKV_SWITCH_INIT();
363
213
                E_CASE( KaxTagTargets, targets )
364
213
                {
365
209
                    msg_Dbg( &vars.sys.demuxer, "|   + Targets" );
366
367
209
                    MKV_SWITCH_CREATE( EbmlTypeDispatcher, TargetsHandler, TagHandlerPayload )
368
209
                    {
369
209
                        MKV_SWITCH_INIT();
370
209
                        E_CASE( KaxTagTargetTypeValue, entry )
371
209
                        {
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
209
                        E_CASE( KaxTagTrackUID, entry )
376
209
                        {
377
44
                            vars.tag.i_tag_type = TRACK_UID;
378
44
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
379
44
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TrackUID: %" PRIu64, vars.tag.i_uid);
380
44
                        }
381
209
                        E_CASE( KaxTagEditionUID, entry )
382
209
                        {
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
209
                        E_CASE( KaxTagChapterUID, entry )
388
209
                        {
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
209
                        E_CASE( KaxTagAttachmentUID, entry )
394
209
                        {
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
209
                        E_CASE( KaxTagTargetType, entry )
400
209
                        {
401
2
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TargetType: %s", entry.GetValue().c_str());
402
2
                        }
403
209
                        E_CASE_DEFAULT( el )
404
209
                        {
405
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
406
0
                        }
407
209
                    };
408
409
209
                    TargetsHandler::Dispatcher().iterate( targets.begin(), targets.end(), &vars );
410
209
                }
411
213
                E_CASE( KaxTagSimple, entry )
412
386
                {
413
386
                    SimpleTag simple;
414
415
386
                    if (vars.obj->ParseSimpleTags( &simple, &entry, vars.target_type ))
416
317
                        vars.tag.simple_tags.push_back( std::move(simple) );
417
386
                }
418
213
                E_CASE_DEFAULT( el )
419
312
                {
420
312
                    msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
421
312
                }
422
213
            };
423
424
213
            TagHandler::Dispatcher().iterate( entry.begin(), entry.end(), &payload );
425
213
            vars.obj->tags.push_back(std::move(tag));
426
213
        }
427
796
        E_CASE_DEFAULT( el )
428
2.20k
        {
429
2.20k
            msg_Dbg( &vars.sys.demuxer, "|   + LoadTag Unknown (%s)", EBML_NAME(&el) );
430
2.20k
        }
431
796
    };
432
433
796
    KaxTagsHandler::Dispatcher().iterate( tags_->begin(), tags_->end(), &payload );
434
796
    msg_Dbg( &sys.demuxer, "loading tags done." );
435
796
}
436
437
/*****************************************************************************
438
 * InformationCreate:
439
 *****************************************************************************/
440
void matroska_segment_c::InformationCreate( )
441
2.06k
{
442
2.06k
    if( !sys.meta )
443
1.95k
        sys.meta = vlc_meta_New();
444
445
2.06k
    if( psz_title )
446
174
    {
447
174
        vlc_meta_SetTitle( sys.meta, psz_title );
448
174
    }
449
2.06k
}
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.04k
{
554
6.04k
    if ( b_preloaded )
555
3.94k
        return false;
556
557
2.10k
    EbmlElement *el = NULL;
558
559
2.10k
    ep.Reset( &sys.demuxer );
560
561
11.6k
    while( ( el = ep.Get() ) != NULL )
562
11.6k
    {
563
11.6k
        if( MKV_IS_ID( el, KaxSeekHead ) )
564
1.36k
        {
565
            /* Multiple allowed */
566
            /* We bail at 10, to prevent possible recursion */
567
1.36k
            msg_Dbg(  &sys.demuxer, "|   + Seek head" );
568
1.36k
            if( i_seekhead_count < 10 )
569
1.36k
            {
570
1.36k
                i_seekhead_position = el->GetElementPosition();
571
1.36k
                ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
572
1.36k
            }
573
1.36k
        }
574
10.2k
        else if( MKV_IS_ID( el, KaxInfo ) )
575
1.38k
        {
576
            /* Multiple allowed, mandatory */
577
1.38k
            msg_Dbg(  &sys.demuxer, "|   + Information" );
578
1.38k
            if( i_info_position < 0 )
579
738
            {
580
738
                ParseInfo( static_cast<KaxInfo*>( el ) );
581
738
                i_info_position = el->GetElementPosition();
582
738
            }
583
1.38k
        }
584
8.85k
        else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) )
585
2.38k
        {
586
            /* Multiple allowed */
587
2.38k
            msg_Dbg(  &sys.demuxer, "|   + Tracks" );
588
2.38k
            if( i_tracks_position < 0 )
589
1.55k
            {
590
1.55k
                ParseTracks( kt_ptr );
591
1.55k
            }
592
2.38k
            if ( tracks.size() == 0 )
593
1
            {
594
1
                msg_Err( &sys.demuxer, "No tracks supported" );
595
1
            }
596
2.38k
            i_tracks_position = el->GetElementPosition();
597
2.38k
        }
598
6.46k
        else if( MKV_CHECKED_PTR_DECL ( cues, KaxCues, el ) )
599
119
        {
600
119
            msg_Dbg(  &sys.demuxer, "|   + Cues" );
601
119
            if( i_cues_position < 0 )
602
64
            {
603
64
                LoadCues( cues );
604
64
                i_cues_position = el->GetElementPosition();
605
64
            }
606
119
        }
607
6.34k
        else if( MKV_CHECKED_PTR_DECL ( cluster_, KaxCluster, el ) )
608
2.07k
        {
609
2.07k
            if( sys.b_seekable &&
610
2.07k
                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.07k
            msg_Dbg( &sys.demuxer, "|   + Cluster" );
616
617
618
2.07k
            if (EnsureDuration(*cluster_))
619
2.07k
            {
620
2.07k
                cluster = cluster_;
621
622
                // add first cluster as trusted seekpoint for all tracks
623
2.07k
                for( tracks_map_t::const_iterator it = tracks.begin();
624
5.75k
                     it != tracks.end(); ++it )
625
3.68k
                {
626
3.68k
                    _seeker.add_seekpoint( it->first,
627
3.68k
                    SegmentSeeker::Seekpoint( cluster->GetElementPosition(), -1,
628
3.68k
                                              SegmentSeeker::Seekpoint::TrustLevel::QUESTIONABLE ) );
629
3.68k
                }
630
631
                /* stop pre-parsing the stream */
632
2.07k
                break;
633
2.07k
            }
634
2.07k
        }
635
4.27k
        else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
636
53
        {
637
53
            msg_Dbg( &sys.demuxer, "|   + Attachments" );
638
53
            if( i_attachments_position < 0 )
639
33
            {
640
33
                ParseAttachments( ka_ptr );
641
33
                i_attachments_position = el->GetElementPosition();
642
33
            }
643
53
        }
644
4.21k
        else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
645
414
        {
646
414
            msg_Dbg( &sys.demuxer, "|   + Chapters" );
647
414
            if( i_chapters_position < 0 )
648
206
            {
649
206
                ParseChapters( chapters );
650
206
                i_chapters_position = el->GetElementPosition();
651
206
            }
652
414
        }
653
3.80k
        else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
654
1.25k
        {
655
1.25k
            msg_Dbg( &sys.demuxer, "|   + Tags" );
656
1.25k
            if(tags.empty ())
657
1.16k
            {
658
1.16k
                LoadTags( tags_ );
659
1.16k
            }
660
1.25k
        }
661
2.55k
        else if( MKV_IS_ID ( el, EbmlVoid ) )
662
2.55k
            msg_Dbg( &sys.demuxer, "|   + Void" );
663
637
        else
664
637
            msg_Dbg( &sys.demuxer, "|   + Preload Unknown (%s)", EBML_NAME(el) );
665
11.6k
    }
666
667
2.10k
    ComputeTrackPriority();
668
669
2.10k
    b_preloaded = true;
670
671
2.10k
    return true;
672
6.04k
}
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.09k
{
677
3.09k
    int64_t     i_sav_position = static_cast<int64_t>( es.I_O().getFilePointer() );
678
3.09k
    EbmlElement *el;
679
680
3.09k
    es.I_O().setFilePointer( i_element_position, seek_beginning );
681
3.09k
    el = es.FindNextID( ClassInfos, 0xFFFFFFFFL);
682
683
3.09k
    if( el == nullptr || el->IsDummy() )
684
1.71k
    {
685
1.71k
        msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" );
686
1.71k
        es.I_O().setFilePointer( i_sav_position, seek_beginning );
687
1.71k
        delete el;
688
1.71k
        return false;
689
1.71k
    }
690
691
1.38k
    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.38k
    else if( MKV_CHECKED_PTR_DECL ( ki_ptr, KaxInfo, el ) ) // FIXME
705
561
    {
706
        /* Multiple allowed, mandatory */
707
561
        msg_Dbg( &sys.demuxer, "|   + Information" );
708
561
        if( i_info_position < 0 )
709
560
        {
710
560
            ParseInfo( ki_ptr );
711
560
            i_info_position = i_element_position;
712
560
        }
713
561
    }
714
827
    else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) // FIXME
715
537
    {
716
        /* Multiple allowed */
717
537
        msg_Dbg( &sys.demuxer, "|   + Tracks" );
718
537
        if( i_tracks_position < 0 )
719
537
            ParseTracks( kt_ptr );
720
537
        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
537
        i_tracks_position = i_element_position;
728
537
    }
729
290
    else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) )
730
63
    {
731
63
        msg_Dbg( &sys.demuxer, "|   + Cues" );
732
63
        if( i_cues_position < 0 )
733
63
        {
734
63
            LoadCues( kc_ptr );
735
63
            i_cues_position = i_element_position;
736
63
        }
737
63
    }
738
227
    else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
739
20
    {
740
20
        msg_Dbg( &sys.demuxer, "|   + Attachments" );
741
20
        if( i_attachments_position < 0 )
742
20
        {
743
20
            ParseAttachments( ka_ptr );
744
20
            i_attachments_position = i_element_position;
745
20
        }
746
20
    }
747
207
    else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
748
144
    {
749
144
        msg_Dbg( &sys.demuxer, "|   + Chapters" );
750
144
        if( i_chapters_position < 0 )
751
144
        {
752
144
            ParseChapters( chapters );
753
144
            i_chapters_position = i_element_position;
754
144
        }
755
144
    }
756
63
    else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
757
63
    {
758
63
        msg_Dbg( &sys.demuxer, "|   + Tags" );
759
63
        if(tags.empty ())
760
63
        {
761
63
            LoadTags( tags_ );
762
63
        }
763
63
    }
764
0
    else
765
0
    {
766
0
        msg_Dbg( &sys.demuxer, "|   + LoadSeekHeadItem Unknown (%s)", EBML_NAME(el) );
767
0
    }
768
1.38k
    delete el;
769
770
1.38k
    es.I_O().setFilePointer( i_sav_position, seek_beginning );
771
1.38k
    return true;
772
1.38k
}
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.09k
{
776
2.09k
    SegmentSeeker::tracks_seekpoint_t seekpoints;
777
778
2.09k
    SegmentSeeker::fptr_t i_seek_position = std::numeric_limits<SegmentSeeker::fptr_t>::max();
779
2.09k
    vlc_tick_t i_mk_seek_time = -1;
780
2.09k
    vlc_tick_t i_mk_date = i_absolute_mk_date - i_mk_time_offset;
781
2.09k
    SegmentSeeker::track_ids_t selected_tracks;
782
2.09k
    SegmentSeeker::track_ids_t priority;
783
784
    // reset information for all tracks //
785
786
5.79k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
787
3.70k
    {
788
3.70k
        mkv_track_t &track = *it->second;
789
790
3.70k
        track.i_skip_until_fpos = std::numeric_limits<uint64_t>::max();
791
3.70k
        if( track.i_last_dts != VLC_TICK_INVALID )
792
25
            track.b_discontinuity = true;
793
3.70k
        track.i_last_dts        = VLC_TICK_INVALID;
794
795
3.70k
        bool selected;
796
3.70k
        if (track.p_es == NULL)
797
45
            selected = false;
798
3.66k
        else
799
3.66k
            es_out_Control( demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &selected );
800
3.70k
        if ( selected )
801
3.66k
            selected_tracks.push_back( track.i_number );
802
3.70k
    }
803
804
2.09k
    if ( selected_tracks.empty() )
805
15
    {
806
15
        selected_tracks = priority_tracks;
807
15
        priority = priority_tracks;
808
15
    }
809
2.07k
    else
810
2.07k
    {
811
2.07k
        std::set_intersection(priority_tracks.begin(),priority_tracks.end(),
812
2.07k
                              selected_tracks.begin(),selected_tracks.end(),
813
2.07k
                              std::back_inserter(priority));
814
2.07k
        if (priority.empty()) // no video selected ?
815
20
            priority = selected_tracks;
816
2.07k
    }
817
818
    // find appropriate seekpoints //
819
820
2.09k
    try {
821
2.09k
        seekpoints = _seeker.get_seekpoints( *this, i_mk_date, priority, selected_tracks );
822
2.09k
    }
823
2.09k
    catch( std::exception const& e )
824
2.09k
    {
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.75k
    for( SegmentSeeker::tracks_seekpoint_t::const_iterator it = seekpoints.begin(); it != seekpoints.end(); ++it )
832
3.65k
    {
833
3.65k
        tracks_map_t::iterator trackit = tracks.find( it->first );
834
3.65k
        if ( trackit == tracks.end() )
835
0
            continue; // there were blocks with unknown tracks
836
837
3.65k
        if( i_seek_position > it->second.fpos )
838
2.33k
        {
839
2.33k
            i_seek_position = it->second.fpos;
840
2.33k
            i_mk_seek_time  = it->second.pts;
841
2.33k
        }
842
843
        // blocks that will be not be read until this fpos
844
3.65k
        if ( b_accurate )
845
3.65k
            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.65k
        if (it->second.pts != -1)
849
1.24k
            trackit->second->i_last_dts        = it->second.pts + i_mk_time_offset;
850
851
3.65k
        msg_Dbg( &sys.demuxer, "seek: preroll{ track: %u, pts: %" PRId64 ", fpos: %" PRIu64 " skip: %" PRIu64 "} ",
852
3.65k
          it->first, it->second.pts, it->second.fpos, trackit->second->i_skip_until_fpos );
853
3.65k
    }
854
855
2.09k
    if ( i_seek_position == std::numeric_limits<SegmentSeeker::fptr_t>::max() )
856
12
        return false;
857
858
    // propagate seek information //
859
860
2.08k
    sys.i_pcr           = VLC_TICK_INVALID;
861
2.08k
    sys.i_pts           = VLC_TICK_0 + i_mk_seek_time + i_mk_time_offset;
862
2.08k
    if (b_accurate)
863
2.08k
        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.08k
    _seeker.mkv_jump_to( *this, i_seek_position );
870
871
    // debug diagnostics //
872
873
2.08k
    msg_Dbg( &sys.demuxer, "seek: preroll{ req: %" PRId64 ", start-pts: %" PRId64 ", start-fpos: %" PRIu64 "} ",
874
2.08k
      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.08k
    es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts );
878
2.08k
    return true;
879
2.09k
}
880
881
882
mkv_track_t * matroska_segment_c::FindTrackByBlock(
883
                                             const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
884
273k
{
885
273k
    tracks_map_t::iterator track_it;
886
887
273k
    if (p_block != NULL)
888
146k
        track_it = tracks.find( p_block->TrackNum() );
889
127k
    else if( p_simpleblock != NULL)
890
127k
        track_it = tracks.find( p_simpleblock->TrackNum() );
891
0
    else
892
0
        track_it = tracks.end();
893
894
273k
    if (track_it == tracks.end())
895
3.91k
        return NULL;
896
897
269k
    return track_it->second.get();
898
273k
}
899
900
void matroska_segment_c::ComputeTrackPriority()
901
2.10k
{
902
2.10k
    bool b_has_default_video = false;
903
2.10k
    bool b_has_default_audio = false;
904
    /* check for default */
905
5.91k
    for( tracks_map_t::const_iterator it = tracks.begin(); it != tracks.end();
906
3.80k
         ++it )
907
3.80k
    {
908
3.80k
        mkv_track_t &track = *it->second;
909
910
3.80k
        bool flag = track.b_enabled && ( track.b_default || track.b_forced );
911
912
3.80k
        switch( track.fmt.i_cat )
913
3.80k
        {
914
1.81k
            case VIDEO_ES: b_has_default_video |= flag; break;
915
1.38k
            case AUDIO_ES: b_has_default_audio |= flag; break;
916
610
            default: break; // ignore
917
3.80k
        }
918
3.80k
    }
919
920
5.91k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
921
3.80k
    {
922
3.80k
        tracks_map_t::key_type track_id = it->first;
923
3.80k
        mkv_track_t          & track    = *it->second;
924
925
3.80k
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
926
43
        {
927
43
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
928
43
            track.p_es = NULL;
929
43
            continue;
930
43
        }
931
3.76k
        else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) )
932
539
        {
933
539
            track.b_default = true;
934
539
            b_has_default_video = true;
935
539
        }
936
3.22k
        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.76k
        if( unlikely( !track.b_enabled ) )
942
0
            track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
943
3.76k
        else if( track.b_forced )
944
0
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
945
3.76k
        else if( track.b_default )
946
3.21k
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
947
551
        else
948
551
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
949
950
        /* Avoid multivideo tracks when unnecessary */
951
3.76k
        if( track.fmt.i_cat == VIDEO_ES )
952
1.79k
            track.fmt.i_priority--;
953
3.76k
    }
954
955
    // find track(s) with highest priority //
956
2.10k
    {
957
2.10k
        int   score = -1;
958
2.10k
        int es_type = -1;
959
960
5.91k
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
961
3.80k
        {
962
3.80k
            int track_score = -1;
963
964
3.80k
            switch( it->second->fmt.i_cat )
965
3.80k
            {
966
1.81k
                case VIDEO_ES: ++track_score;
967
                /* fallthrough */
968
3.19k
                case AUDIO_ES: ++track_score;
969
                /* fallthrough */
970
3.78k
                case   SPU_ES: ++track_score;
971
                /* fallthrough */
972
3.80k
                default:
973
3.80k
                  if( score < track_score )
974
2.12k
                  {
975
2.12k
                      es_type = it->second->fmt.i_cat;
976
2.12k
                      score   = track_score;
977
2.12k
                  }
978
3.80k
            }
979
3.80k
        }
980
981
5.91k
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
982
3.80k
        {
983
3.80k
            if( it->second->fmt.i_cat == es_type )
984
2.11k
                priority_tracks.push_back( it->first );
985
3.80k
        }
986
2.10k
    }
987
2.10k
}
988
989
bool matroska_segment_c::EnsureDuration(KaxCluster & fromCluster)
990
2.07k
{
991
2.07k
    if ( i_duration > 0 )
992
610
        return true;
993
994
1.46k
    i_duration = -1;
995
996
1.46k
    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.46k
    uint64_t i_current_position = es.I_O().getFilePointer();
1003
1.46k
    uint64_t i_last_cluster_pos = fromCluster.GetElementPosition();
1004
1005
    // find the last Cluster from the Cues
1006
1007
1.46k
    if ( b_cues && _seeker._cluster_positions.size() )
1008
24
        i_last_cluster_pos = *_seeker._cluster_positions.rbegin();
1009
1.44k
    else if( !fromCluster.IsFiniteSize() )
1010
999
    {
1011
        // make sure our first Cluster has a timestamp
1012
999
        return ParseCluster( &fromCluster, false, SCOPE_PARTIAL_DATA );
1013
999
    }
1014
1015
470
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1016
1017
470
    EbmlParser eparser ( &es, segment, &sys.demuxer );
1018
1019
    // locate the definitely last cluster in the stream
1020
1021
11.0k
    while( EbmlElement* el = eparser.Get() )
1022
10.5k
    {
1023
10.5k
        if( !el->IsFiniteSize() && el->GetElementPosition() != i_last_cluster_pos )
1024
29
        {
1025
29
            es.I_O().setFilePointer( i_current_position, seek_beginning );
1026
29
            return true;
1027
29
        }
1028
1029
10.5k
        if( MKV_IS_ID( el, KaxCluster ) )
1030
7.02k
        {
1031
7.02k
            i_last_cluster_pos = el->GetElementPosition();
1032
7.02k
            if ( i_last_cluster_pos == fromCluster.GetElementPosition() )
1033
446
            {
1034
                // make sure our first Cluster has a timestamp
1035
446
                if (!ParseCluster( &fromCluster, true, SCOPE_PARTIAL_DATA ))
1036
7
                    return false;
1037
446
            }
1038
7.02k
        }
1039
10.5k
    }
1040
1041
    // find the last timecode in the Cluster
1042
1043
434
    eparser.Reset( &sys.demuxer );
1044
434
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1045
1046
434
    EbmlElement* el = eparser.Get();
1047
434
    MKV_CHECKED_PTR_DECL( p_last_cluster, KaxCluster, el );
1048
1049
434
    if( p_last_cluster &&
1050
410
        ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA ) )
1051
403
    {
1052
        // use the last block + duration
1053
403
        uint64_t i_last_timecode = p_last_cluster->GlobalTimestamp();
1054
403
        for (auto l : *p_last_cluster)
1055
8.22k
        {
1056
8.22k
            if( MKV_CHECKED_PTR_DECL ( simpleblock, KaxSimpleBlock, l ) )
1057
2.22k
            {
1058
2.22k
                simpleblock->SetParent( *p_last_cluster );
1059
2.22k
                i_last_timecode = std::max(i_last_timecode, simpleblock->GlobalTimestamp());
1060
2.22k
            }
1061
5.99k
            else if( MKV_CHECKED_PTR_DECL_CONST ( group, KaxBlockGroup, l ) )
1062
501
            {
1063
501
                uint64_t i_group_timecode = 0;
1064
501
                for (auto g : *group)
1065
1.03k
                {
1066
1.03k
                    if( MKV_CHECKED_PTR_DECL ( block, KaxBlock, g ) )
1067
464
                    {
1068
464
                        block->SetParent( *p_last_cluster );
1069
464
                        i_group_timecode += block->GlobalTimestamp();
1070
464
                    }
1071
569
                    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
501
                i_last_timecode = std::max(i_last_timecode, i_group_timecode);
1077
501
            }
1078
8.22k
        }
1079
1080
403
        i_duration = VLC_TICK_FROM_NS( i_last_timecode - fromCluster.GlobalTimestamp() );
1081
403
        msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, SEC_FROM_VLC_TICK(i_duration) );
1082
403
    }
1083
1084
    // get back to the reading position we were at before looking for a duration
1085
434
    es.I_O().setFilePointer( i_current_position, seek_beginning );
1086
434
    return true;
1087
470
}
1088
1089
bool matroska_segment_c::ESCreate()
1090
2.06k
{
1091
    /* add all es */
1092
2.06k
    msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) );
1093
1094
2.06k
    mkv_track_t *default_tracks[ES_CATEGORY_COUNT] = {};
1095
5.74k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1096
3.67k
    {
1097
3.67k
        tracks_map_t::key_type   track_id = it->first;
1098
3.67k
        mkv_track_t            & track    = *it->second;
1099
1100
3.67k
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
1101
43
        {
1102
43
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
1103
43
            track.p_es = NULL;
1104
43
            continue;
1105
43
        }
1106
3.62k
        track.fmt.i_id = static_cast<int>( track_id );
1107
1108
3.62k
        if( !track.p_es )
1109
3.62k
        {
1110
3.62k
            track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
1111
1112
3.62k
            if( track.p_es &&
1113
3.62k
                !sys.ev.AddTrack( track ) )
1114
1.76k
            {
1115
1.76k
                msg_Warn( &sys.demuxer, "Could not register events, interactive menus will not work");
1116
1.76k
            }
1117
3.62k
        }
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.62k
        if( track.b_default || track.b_forced )
1125
3.13k
        {
1126
3.13k
            mkv_track_t *&default_track = default_tracks[track.fmt.i_cat];
1127
3.13k
            if( !default_track || track.b_default )
1128
3.13k
                default_track = &track;
1129
3.13k
        }
1130
3.62k
    }
1131
1132
2.06k
    for( mkv_track_t *track : default_tracks )
1133
10.3k
    {
1134
10.3k
        if( track )
1135
3.13k
            es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track->p_es );
1136
10.3k
    }
1137
1138
2.06k
    return true;
1139
2.06k
}
1140
1141
void matroska_segment_c::ESDestroy( )
1142
2.06k
{
1143
2.06k
    sys.ev.AbortThread();
1144
1145
5.74k
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1146
3.67k
    {
1147
3.67k
        mkv_track_t & track = *it->second;
1148
1149
3.67k
        if( track.p_es != NULL )
1150
3.62k
        {
1151
3.62k
            es_out_Del( sys.demuxer.out, track.p_es );
1152
3.62k
            sys.ev.DelTrack( track );
1153
3.62k
            track.p_es = NULL;
1154
3.62k
        }
1155
3.67k
    }
1156
2.06k
}
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
                                  uint64_t *pi_duration )
1162
77.0k
{
1163
77.0k
    pp_simpleblock = NULL;
1164
77.0k
    pp_block = NULL;
1165
77.0k
    pp_additions = NULL;
1166
1167
77.0k
    *pb_key_picture         = true;
1168
77.0k
    *pb_discardable_picture = false;
1169
77.0k
    *pi_duration = 0;
1170
1171
77.0k
    uint64_t duration = 0;
1172
77.0k
    int64_t duration_padding = 0;
1173
1174
77.0k
    struct BlockPayload {
1175
77.0k
        matroska_segment_c * const obj;
1176
77.0k
        EbmlParser         * const ep;
1177
77.0k
        demux_t            * const p_demuxer;
1178
77.0k
        KaxBlock          *& block;
1179
77.0k
        KaxSimpleBlock    *& simpleblock;
1180
77.0k
        KaxBlockAdditions *& additions;
1181
1182
77.0k
        uint64_t           & i_duration;
1183
77.0k
        int64_t            & duration_padding;
1184
77.0k
        bool               & b_key_picture;
1185
77.0k
        bool               & b_discardable_picture;
1186
77.0k
        bool                 b_cluster_timecode;
1187
1188
77.0k
    } payload = {
1189
77.0k
        this, &ep, &sys.demuxer, pp_block, pp_simpleblock, pp_additions,
1190
77.0k
        duration, duration_padding, *pb_key_picture, *pb_discardable_picture, true
1191
77.0k
    };
1192
1193
77.0k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l1, BlockPayload )
1194
77.0k
    {
1195
77.0k
        MKV_SWITCH_INIT();
1196
1197
77.0k
        E_CASE( KaxCluster, kcluster )
1198
77.0k
        {
1199
30.6k
            vars.obj->cluster = &kcluster;
1200
30.6k
            vars.b_cluster_timecode = false;
1201
30.6k
            vars.ep->Down ();
1202
30.6k
        }
1203
77.0k
        E_CASE( KaxCues, kcue )
1204
77.0k
        {
1205
1.07k
            VLC_UNUSED( kcue );
1206
1.07k
            msg_Warn( vars.p_demuxer, "find KaxCues FIXME" );
1207
1.07k
        }
1208
77.0k
        E_CASE_DEFAULT(element)
1209
77.0k
        {
1210
29.4k
            msg_Dbg( vars.p_demuxer, "Unknown (%s)", EBML_NAME(&element) );
1211
29.4k
        }
1212
77.0k
    };
1213
1214
77.0k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l2, BlockPayload )
1215
77.0k
    {
1216
77.0k
        MKV_SWITCH_INIT();
1217
1218
77.0k
        E_CASE( KaxClusterTimestamp, ktimecode )
1219
77.0k
        {
1220
54.3k
            ktimecode.ReadData( vars.obj->es.I_O(), SCOPE_ALL_DATA );
1221
54.3k
            vars.obj->cluster->InitTimestamp( static_cast<uint64_t>( ktimecode ), vars.obj->i_timescale );
1222
54.3k
            vars.obj->_seeker.add_cluster( vars.obj->cluster );
1223
54.3k
            vars.b_cluster_timecode = true;
1224
54.3k
        }
1225
77.0k
        E_CASE( KaxClusterSilentTracks, ksilent )
1226
77.0k
        {
1227
3
            vars.ep->Down ();
1228
1229
3
            VLC_UNUSED( ksilent );
1230
3
        }
1231
77.0k
        E_CASE( KaxBlockGroup, kbgroup )
1232
77.0k
        {
1233
44.9k
            if( vars.b_cluster_timecode == false )
1234
278
            {
1235
278
                msg_Warn( vars.p_demuxer, "ignoring KaxBlockGroup prior to mandatory Timecode" );
1236
278
                return;
1237
278
            }
1238
1239
44.6k
            vars.obj->i_block_pos = kbgroup.GetElementPosition();
1240
44.6k
            vars.ep->Down ();
1241
44.6k
        }
1242
77.0k
        E_CASE( KaxSimpleBlock, ksblock )
1243
77.0k
        {
1244
40.7k
            if( vars.b_cluster_timecode == false )
1245
29
            {
1246
29
                msg_Warn( vars.p_demuxer, "ignoring SimpleBlock prior to mandatory Timecode" );
1247
29
                return;
1248
29
            }
1249
1250
40.6k
            filepos_t read = 0;
1251
40.6k
            try {
1252
40.6k
                read = ksblock.ReadData( vars.obj->es.I_O() );
1253
40.6k
            } catch(...) {
1254
0
            }
1255
40.6k
            if (read == 0 && ksblock.GetSize() != 0) {
1256
2.50k
                msg_Err( vars.p_demuxer,"Error while reading %s",  EBML_NAME(&ksblock) );
1257
2.50k
                ksblock.ReleaseFrames();
1258
2.50k
                return;
1259
2.50k
            }
1260
38.1k
            vars.simpleblock = &ksblock;
1261
38.1k
            vars.simpleblock->SetParent( *vars.obj->cluster );
1262
1263
38.1k
            if( ksblock.IsKeyframe() )
1264
16.6k
            {
1265
16.6k
                bool const b_valid_track = vars.obj->FindTrackByBlock( NULL, &ksblock ) != NULL;
1266
16.6k
                if (b_valid_track)
1267
16.1k
                    vars.obj->_seeker.add_seekpoint( ksblock.TrackNum(),
1268
16.1k
                        SegmentSeeker::Seekpoint( ksblock.GetElementPosition(), VLC_TICK_FROM_NS(ksblock.GlobalTimestamp()) ) );
1269
16.6k
            }
1270
38.1k
        }
1271
77.0k
    };
1272
1273
77.0k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l3, BlockPayload )
1274
77.0k
    {
1275
77.0k
        MKV_SWITCH_INIT();
1276
1277
77.0k
        E_CASE( KaxBlock, kblock )
1278
77.0k
        {
1279
38.7k
            filepos_t read = 0;
1280
38.7k
            try {
1281
38.7k
                read = kblock.ReadData( vars.obj->es.I_O() );
1282
38.7k
            } catch(...) {
1283
0
            }
1284
38.7k
            if (unlikely(read == 0) && kblock.GetSize() != 0) {
1285
123
                msg_Err( vars.p_demuxer,"Error while reading %s",  EBML_NAME(&kblock) );
1286
123
                kblock.ReleaseFrames();
1287
123
                return;
1288
123
            }
1289
38.6k
            vars.block = &kblock;
1290
38.6k
            vars.block->SetParent( *vars.obj->cluster );
1291
1292
38.6k
            const mkv_track_t *p_track = vars.obj->FindTrackByBlock( &kblock, NULL );
1293
38.6k
            if( p_track != NULL && p_track->fmt.i_cat == SPU_ES )
1294
181
            {
1295
181
                vars.obj->_seeker.add_seekpoint( kblock.TrackNum(),
1296
181
                    SegmentSeeker::Seekpoint( kblock.GetElementPosition(), VLC_TICK_FROM_NS(kblock.GlobalTimestamp()) ) );
1297
181
            }
1298
1299
38.6k
            vars.ep->Keep ();
1300
38.6k
        }
1301
77.0k
        E_CASE( KaxBlockAdditions, kadditions )
1302
77.0k
        {
1303
2.12k
            if ( vars.obj->ReadMaster( kadditions ) )
1304
2.12k
            {
1305
2.12k
                vars.additions = &kadditions;
1306
2.12k
                vars.ep->Keep ();
1307
2.12k
            }
1308
2.12k
        }
1309
77.0k
        E_CASE( KaxBlockDuration, kduration )
1310
77.0k
        {
1311
6.04k
            kduration.ReadData( vars.obj->es.I_O() );
1312
6.04k
            vars.i_duration = static_cast<uint64_t>( kduration );
1313
6.04k
        }
1314
77.0k
        E_CASE( KaxReferenceBlock, kreference )
1315
77.0k
        {
1316
12.3k
           kreference.ReadData( vars.obj->es.I_O() );
1317
1318
12.3k
           if( vars.b_key_picture )
1319
11.9k
               vars.b_key_picture = false;
1320
370
           else if( static_cast<int64_t>( kreference ) )
1321
370
               vars.b_discardable_picture = true;
1322
12.3k
        }
1323
77.0k
        E_CASE( KaxClusterSilentTrackNumber, kstrackn )
1324
77.0k
        {
1325
0
            VLC_UNUSED( kstrackn );
1326
0
            VLC_UNUSED( vars );
1327
0
        }
1328
77.0k
#if LIBMATROSKA_VERSION >= 0x010401
1329
77.0k
        E_CASE( KaxDiscardPadding, kdiscardp )
1330
77.0k
        {
1331
0
            kdiscardp.ReadData( vars.obj->es.I_O() );
1332
0
            vars.duration_padding = static_cast<int64_t>( kdiscardp );
1333
0
        }
1334
77.0k
#endif
1335
77.0k
        E_CASE_DEFAULT( element )
1336
77.0k
        {
1337
130
            VLC_UNUSED(element);
1338
1339
130
            msg_Warn( vars.p_demuxer, "unknown element at { fpos: %" PRId64 ", '%s' }",
1340
130
              element.GetElementPosition(), EBML_NAME( &element ) );
1341
130
        }
1342
77.0k
    };
1343
1344
77.0k
    static EbmlTypeDispatcher const * const dispatchers[] = {
1345
77.0k
        &BlockGetHandler_l1::Dispatcher(),
1346
77.0k
        &BlockGetHandler_l2::Dispatcher(),
1347
77.0k
        &BlockGetHandler_l3::Dispatcher()
1348
77.0k
    };
1349
1350
77.0k
    for( ;; )
1351
419k
    {
1352
419k
        EbmlElement *el = NULL;
1353
419k
        int         i_level;
1354
1355
419k
        if( pp_simpleblock != NULL || ((el = ep.Get()) == NULL && pp_block != NULL) )
1356
76.8k
        {
1357
            /* Check blocks validity to protect against broken files */
1358
76.8k
            const mkv_track_t *p_track = FindTrackByBlock( pp_block , pp_simpleblock );
1359
76.8k
            if( p_track == NULL )
1360
2.01k
            {
1361
2.01k
                ep.Unkeep();
1362
2.01k
                pp_simpleblock = NULL;
1363
2.01k
                pp_block = NULL;
1364
2.01k
                continue;
1365
2.01k
            }
1366
74.8k
            if( pp_simpleblock != NULL )
1367
37.5k
            {
1368
37.5k
                *pb_key_picture         = pp_simpleblock->IsKeyframe();
1369
37.5k
                *pb_discardable_picture = pp_simpleblock->IsDiscardable();
1370
37.5k
            }
1371
            /* We have block group let's check if the picture is a keyframe */
1372
37.2k
            else if( *pb_key_picture )
1373
25.3k
            {
1374
25.3k
                if( p_track->fmt.i_codec == VLC_CODEC_THEORA )
1375
1.24k
                {
1376
1.24k
                    DataBuffer *    p_data = &pp_block->GetBuffer(0);
1377
1.24k
                    const uint8_t * p_buff = p_data->Buffer();
1378
                    /* if the second bit of a Theora frame is 1
1379
                       it's not a keyframe */
1380
1.24k
                    if( p_data->Size() && p_buff )
1381
1.23k
                    {
1382
1.23k
                        if( p_buff[0] & 0x40 )
1383
984
                            *pb_key_picture = false;
1384
1.23k
                    }
1385
4
                    else
1386
4
                        *pb_key_picture = false;
1387
1.24k
                }
1388
25.3k
            }
1389
1390
            /* A negative DiscardPadding designates padding at the start of
1391
             * the block, which we don't handle; some files in the wild also
1392
             * carry bogus negative values due to encoder bugs. Never let it
1393
             * extend the block duration. */
1394
74.8k
            if ( duration_padding < 0)
1395
0
            {
1396
0
                msg_Warn( &sys.demuxer, "ignoring negative DiscardPadding (%" PRId64 ")", duration_padding );
1397
0
                *pi_duration = duration;
1398
0
            }
1399
74.8k
            else if( duration < (uint64_t)duration_padding )
1400
0
                *pi_duration = 0;
1401
74.8k
            else
1402
74.8k
                *pi_duration = duration - duration_padding;
1403
1404
74.8k
            return VLC_SUCCESS;
1405
76.8k
        }
1406
1407
343k
        i_level = ep.GetLevel();
1408
1409
343k
        if( el == NULL )
1410
78.2k
        {
1411
78.2k
            if( i_level > 1 )
1412
76.0k
            {
1413
76.0k
                ep.Up();
1414
76.0k
                continue;
1415
76.0k
            }
1416
2.20k
            msg_Warn( &sys.demuxer, "EOF" );
1417
2.20k
            return VLC_EGENERIC;
1418
78.2k
        }
1419
1420
        /* Verify that we are still inside our cluster
1421
         * It can happens with broken files and when seeking
1422
         * without index */
1423
264k
        if( i_level > 1 )
1424
203k
        {
1425
203k
            if( cluster && !ep.IsTopPresent( cluster ) )
1426
0
            {
1427
0
                msg_Warn( &sys.demuxer, "Unexpected escape from current cluster" );
1428
0
                cluster = NULL;
1429
0
            }
1430
203k
            if( !cluster )
1431
0
                continue;
1432
203k
        }
1433
1434
        /* do parsing */
1435
1436
264k
        try {
1437
264k
            switch( i_level )
1438
264k
            {
1439
144k
                case 2:
1440
                /* fallthrough */
1441
203k
                case 3:
1442
203k
                    if( unlikely( !el->ValidateSize() || ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) )
1443
0
                    {
1444
0
                        msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1445
0
                        ep.Up();
1446
1447
0
                        if ( i_level == 2 )
1448
0
                            break;
1449
1450
0
                        ep.Unkeep();
1451
0
                        pp_simpleblock = NULL;
1452
0
                        pp_block = NULL;
1453
1454
0
                        break;
1455
0
                    }
1456
                    /* fallthrough */
1457
264k
                case 1:
1458
264k
                    {
1459
264k
                        EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1];
1460
264k
                        dispatcher->send( el, &payload );
1461
264k
                    }
1462
264k
                    break;
1463
1464
0
                default:
1465
0
                    msg_Err( &sys.demuxer, "invalid level = %d", i_level );
1466
0
                    return VLC_EGENERIC;
1467
264k
            }
1468
264k
        }
1469
264k
        catch (int ret_code)
1470
264k
        {
1471
0
            return ret_code;
1472
0
        }
1473
264k
        catch (...)
1474
264k
        {
1475
0
            msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1476
0
            ep.Up();
1477
0
            ep.Unkeep();
1478
0
            pp_simpleblock = NULL;
1479
            pp_block = NULL;
1480
0
        }
1481
264k
    }
1482
77.0k
}
1483
1484
} // namespace