Coverage Report

Created: 2026-04-12 07:27

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