Coverage Report

Created: 2025-11-14 06:42

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