Coverage Report

Created: 2026-06-30 07:56

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