virtual_segment.cpp 20.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*****************************************************************************
 * mkv.cpp : matroska demuxer
 *****************************************************************************
 * Copyright (C) 2003-2004 the VideoLAN team
 * $Id$
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
Denis Charmet's avatar
Denis Charmet committed
24
#include <vector>
25

26
#include "demux.hpp"
27

Denis Charmet's avatar
Denis Charmet committed
28
29
/* FIXME move this */
matroska_segment_c * getSegmentbyUID( KaxSegmentUID * p_uid, std::vector<matroska_segment_c*> *segments )
30
{
Denis Charmet's avatar
Denis Charmet committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    for( size_t i = 0; i < (*segments).size(); i++ )
    {
        if( *p_uid == *((*segments)[i]->p_segment_uid) )
            return (*segments)[i];
    }
    return NULL;
}

virtual_chapter_c * virtual_chapter_c::CreateVirtualChapter( chapter_item_c * p_chap,
                                                             matroska_segment_c * p_main_segment,
                                                             std::vector<matroska_segment_c*> * segments,
                                                             int64_t * usertime_offset, bool b_ordered)
{
    matroska_segment_c * p_segment = p_main_segment;
45

Denis Charmet's avatar
Denis Charmet committed
46
47
48
49
50
    if( !p_chap )
    {
        /* Dummy chapter use the whole segment */
        return new virtual_chapter_c( p_segment, NULL, 0, p_segment->i_duration*1000 );
    }
51

Denis Charmet's avatar
Denis Charmet committed
52
53
    int64_t start = ( b_ordered )? *usertime_offset : p_chap->i_start_time;
    int64_t stop = ( b_ordered )? ( *usertime_offset + p_chap->i_end_time - p_chap->i_start_time ) : p_chap->i_end_time;
54

Denis Charmet's avatar
Denis Charmet committed
55
56
    if( p_chap->p_segment_uid && 
       ( !( p_segment = getSegmentbyUID( (KaxSegmentUID*) p_chap->p_segment_uid,segments ) ) || !b_ordered ) )
57
    {
Denis Charmet's avatar
Denis Charmet committed
58
59
60
61
        msg_Warn( &p_main_segment->sys.demuxer,
                  "Couldn't find segment 0x%x or not ordered... - ignoring chapter %s",
                  *( (uint32_t *) p_chap->p_segment_uid->GetBuffer() ),p_chap->psz_name.c_str() );
        return NULL;
62
    }
Denis Charmet's avatar
Denis Charmet committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

    /* Preload segment */
    if ( !p_segment->b_preloaded )
        p_segment->Preload();

    virtual_chapter_c * p_vchap = new virtual_chapter_c( p_segment, p_chap, start, stop );

    if( !p_vchap )
        return NULL;

    int64_t tmp = *usertime_offset;

    for( size_t i = 0; i < p_chap->sub_chapters.size(); i++ )
    {
        virtual_chapter_c * p_vsubchap = CreateVirtualChapter( p_chap->sub_chapters[i], p_segment, segments, &tmp, b_ordered );

        if( p_vsubchap )
            p_vchap->sub_chapters.push_back( p_vsubchap );
    }

    if( tmp == *usertime_offset )
        *usertime_offset += p_chap->i_end_time - p_chap->i_start_time;
    else
        *usertime_offset = tmp;

    msg_Dbg( &p_main_segment->sys.demuxer,
             "Virtual chapter %s from %"PRId64" to %"PRId64" - segment 0x%x",
             p_chap->psz_name.c_str(), p_vchap->i_virtual_start_time, p_vchap->i_virtual_stop_time,
             *(uint32_t*)p_vchap->p_segment->p_segment_uid->GetBuffer() );

    return p_vchap;
94
}
95

Denis Charmet's avatar
Denis Charmet committed
96
virtual_chapter_c::~virtual_chapter_c()
97
{
Denis Charmet's avatar
Denis Charmet committed
98
99
100
    for( size_t i = 0 ; i < sub_chapters.size(); i++ )
        delete sub_chapters[i];
}
101
102


Denis Charmet's avatar
Denis Charmet committed
103
104
105
106
107
108
109
110
111
112
113
114
virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, std::vector<matroska_segment_c*> *opened_segments)
{
    matroska_segment_c *p_main_segment = (*opened_segments)[0];
    p_edition = p_edit;

    int64_t usertime_offset = 0;

    /* ordered chapters */
    if( p_edition && p_edition->b_ordered )
    {
        b_ordered = true;
        for( size_t i = 0; i < p_edition->sub_chapters.size(); i++ )
115
        {
Denis Charmet's avatar
Denis Charmet committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
            virtual_chapter_c * p_vchap = virtual_chapter_c::CreateVirtualChapter( p_edition->sub_chapters[i],
                                                                                   p_main_segment, opened_segments,
                                                                                   &usertime_offset, b_ordered );
            if( p_vchap )
                chapters.push_back( p_vchap );
        }
        i_duration = chapters[ chapters.size() - 1 ]->i_virtual_stop_time;
    }
    else /* Not ordered or no edition at all */
    {
        b_ordered = false;
        matroska_segment_c * p_cur = p_main_segment;
        virtual_chapter_c * p_vchap = NULL;
        int64_t tmp = 0;

        /* check for prev linked segments */
        /* FIXME to avoid infinite recursion we limit to 5 prev sould be better as parameter */
        for( int limit = 0; limit < 5 && p_cur->p_prev_segment_uid ; limit++ )
        {
            matroska_segment_c * p_prev = NULL;
            if( ( p_prev = getSegmentbyUID( p_cur->p_prev_segment_uid, opened_segments ) ) )
137
            {
Denis Charmet's avatar
Denis Charmet committed
138
139
140
                tmp = 0;
                msg_Dbg( &p_main_segment->sys.demuxer, "Prev segment 0x%x found\n",
                         *(int32_t*)p_cur->p_prev_segment_uid->GetBuffer() );
141

Denis Charmet's avatar
Denis Charmet committed
142
143
144
145
146
147
148
                /* Create virtual_chapter from the first edition if any */
                chapter_item_c * p_chap = ( p_prev->stored_editions.size() > 0 )? ((chapter_item_c *)p_prev->stored_editions[0]) : NULL;

                p_vchap = virtual_chapter_c::CreateVirtualChapter( p_chap, p_prev, opened_segments, &tmp, b_ordered );

                if( p_vchap )
                    chapters.insert( chapters.begin(), p_vchap );
149

Denis Charmet's avatar
Denis Charmet committed
150
151
152
153
                p_cur = p_prev;
            }
            else /* segment not found */
                break;
154
        }
Denis Charmet's avatar
Denis Charmet committed
155
156
157
158
159
160
161
162
163
164
165

        tmp = 0;

        /* Append the main segment */
        p_vchap = virtual_chapter_c::CreateVirtualChapter( (chapter_item_c*) p_edit, p_main_segment,
                                                           opened_segments, &tmp, b_ordered );
        if( p_vchap )
            chapters.push_back( p_vchap );

        /* Append next linked segments */
        for( int limit = 0; limit < 5 && p_cur->p_next_segment_uid; limit++ )
166
        {
Denis Charmet's avatar
Denis Charmet committed
167
168
            matroska_segment_c * p_next = NULL;
            if( ( p_next = getSegmentbyUID( p_cur->p_next_segment_uid, opened_segments ) ) )
169
            {
Denis Charmet's avatar
Denis Charmet committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
                tmp = 0;
                msg_Dbg( &p_main_segment->sys.demuxer, "Next segment 0x%x found\n",
                         *(int32_t*) p_cur->p_next_segment_uid->GetBuffer() );

                /* Create virtual_chapter from the first edition if any */
                chapter_item_c * p_chap = ( p_next->stored_editions.size() > 0 )?( (chapter_item_c *)p_next->stored_editions[0] ) : NULL;

                 p_vchap = virtual_chapter_c::CreateVirtualChapter( p_chap, p_next, opened_segments, &tmp, b_ordered );

                if( p_vchap )
                    chapters.push_back( p_vchap );


                p_cur = p_next;
184
            }
Denis Charmet's avatar
Denis Charmet committed
185
186
            else /* segment not found */
                break;
187
        }
Denis Charmet's avatar
Denis Charmet committed
188
189
190

        /* Retime chapters */
        retimeChapters();
191
    }
Denis Charmet's avatar
Denis Charmet committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

#if MKV_DEBUG
    msg_Dbg( &p_main_segment->sys.demuxer, "-- RECAP-BEGIN --" );
    print();
    msg_Dbg( &p_main_segment->sys.demuxer, "-- RECAP-END --" );
#endif
}

virtual_edition_c::~virtual_edition_c()
{
    for( size_t i = 0; i < chapters.size(); i++ )
        delete chapters[i];
}

void virtual_edition_c::retimeSubChapters( virtual_chapter_c * p_vchap )
{
    int64_t stop_time = p_vchap->i_virtual_stop_time;
    for( size_t i = p_vchap->sub_chapters.size(); i-- > 0; )
    {
        virtual_chapter_c * p_vsubchap = p_vchap->sub_chapters[i];
        p_vsubchap->i_virtual_start_time += p_vchap->i_virtual_start_time;

        /*FIXME we artificially extend stop time if they were there before...*/
        /* Just for comfort*/
        p_vsubchap->i_virtual_stop_time = stop_time;
        stop_time = p_vsubchap->i_virtual_start_time;

        retimeSubChapters( p_vsubchap );
    }
}

void virtual_edition_c::retimeChapters()
{
    /* This function is just meant to be used on unordered chapters */
    if( b_ordered )
        return;

    i_duration = 0;

    /* Sort by start time */
    if( chapters.size() > 1 )
        std::sort( chapters.begin(), chapters.end(), virtual_chapter_c::CompareTimecode );

    /* On non ordered editions we have one top chapter == one segment */
    for( size_t i = 0; i < chapters.size(); i++ )
    {
        virtual_chapter_c * p_vchap = chapters[i];

        p_vchap->i_virtual_start_time = i_duration;
        i_duration += p_vchap->p_segment->i_duration * 1000;
        p_vchap->i_virtual_stop_time = i_duration;

        retimeSubChapters( p_vchap );
    }
}

virtual_segment_c::virtual_segment_c( std::vector<matroska_segment_c*> * p_opened_segments )
{
    /* Main segment */
    matroska_segment_c *p_segment = (*p_opened_segments)[0];
    i_current_edition = 0;
    i_sys_title = 0;
    p_current_chapter = NULL;

    for( size_t i = 0; i < p_segment->stored_editions.size(); i++ )
    {
        /* Get the default edition, if non use the first one */
        if( p_segment->stored_editions[i]->b_default )
            i_current_edition = i;

        /* Create a virtual edition from opened */
        virtual_edition_c * p_vedition = new virtual_edition_c( p_segment->stored_editions[i], p_opened_segments );

        /*FIXME if p_vedition failed...*/

        editions.push_back( p_vedition );
    }
    /*if we don't have edition create a dummy one*/
    if( !p_segment->stored_editions.size() )
    {
        virtual_edition_c * p_vedition = new virtual_edition_c( NULL, p_opened_segments );
        editions.push_back( p_vedition );
    }

    /* Set current chapter */
    p_current_chapter = editions[i_current_edition]->getChapterbyTimecode(0);

}

virtual_segment_c::~virtual_segment_c()
{
    for( size_t i = 0; i < editions.size(); i++ )
        delete editions[i];
}

virtual_chapter_c *virtual_segment_c::BrowseCodecPrivate( unsigned int codec_id,
                                    bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
                                    const void *p_cookie,
                                    size_t i_cookie_size )
{
    virtual_edition_c * p_ved = CurrentEdition();
    if( p_ved )
        return p_ved->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );

    return NULL;
297
298
}

Denis Charmet's avatar
Denis Charmet committed
299
300

virtual_chapter_c * virtual_edition_c::BrowseCodecPrivate( unsigned int codec_id,
301
302
303
                                    bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
                                    const void *p_cookie,
                                    size_t i_cookie_size )
304
{
Denis Charmet's avatar
Denis Charmet committed
305
306
307
308
    if( !p_edition )
        return NULL;

    for( size_t i = 0; i < chapters.size(); i++ )
309
    {
Denis Charmet's avatar
Denis Charmet committed
310
311
        virtual_chapter_c * p_result = chapters[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
        if( p_result )
312
313
314
            return p_result;
    }
    return NULL;
315
316
317
}


Denis Charmet's avatar
Denis Charmet committed
318
319
320
321
322

virtual_chapter_c * virtual_chapter_c::BrowseCodecPrivate( unsigned int codec_id,
                                    bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
                                    const void *p_cookie,
                                    size_t i_cookie_size )
323
{
Denis Charmet's avatar
Denis Charmet committed
324
325
    if( !p_chapter )
        return NULL;
326

Denis Charmet's avatar
Denis Charmet committed
327
328
    if( p_chapter->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size ) )
        return this;
329

Denis Charmet's avatar
Denis Charmet committed
330
331
332
333
334
335
336
    for( size_t i = 0; i < sub_chapters.size(); i++ )
    {
        virtual_chapter_c * p_result = sub_chapters[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
        if( p_result )
            return p_result;
    }
    return NULL;
337
338
}

Denis Charmet's avatar
Denis Charmet committed
339
virtual_chapter_c* virtual_chapter_c::getSubChapterbyTimecode( int64_t time )
340
{
Denis Charmet's avatar
Denis Charmet committed
341
    for( size_t i = 0; i < sub_chapters.size(); i++ )
342
    {
Denis Charmet's avatar
Denis Charmet committed
343
344
        if( time >= sub_chapters[i]->i_virtual_start_time && time < sub_chapters[i]->i_virtual_stop_time )
            return sub_chapters[i]->getSubChapterbyTimecode( time );
345
    }
346

Denis Charmet's avatar
Denis Charmet committed
347
    return this;
348
349
}

Denis Charmet's avatar
Denis Charmet committed
350
virtual_chapter_c* virtual_edition_c::getChapterbyTimecode( int64_t time )
351
{
Denis Charmet's avatar
Denis Charmet committed
352
    for( size_t i = 0; i < chapters.size(); i++ )
353
    {
354
355
356
        if( time >= chapters[i]->i_virtual_start_time &&
            ( chapters[i]->i_virtual_stop_time < 0 || time < chapters[i]->i_virtual_stop_time ) )
            /*with the current implementation only the last chapter can have a negative virtual_stop_time*/
Denis Charmet's avatar
Denis Charmet committed
357
            return chapters[i]->getSubChapterbyTimecode( time );
358
    }
Denis Charmet's avatar
Denis Charmet committed
359
360

    return NULL;
361
362
}

Denis Charmet's avatar
Denis Charmet committed
363
bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
364
{
Denis Charmet's avatar
Denis Charmet committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    demux_sys_t & sys = *demux.p_sys;
    virtual_chapter_c *p_cur_chapter;
    virtual_edition_c * p_cur_edition = editions[ i_current_edition ];

    bool b_has_seeked = false;

    p_cur_chapter = p_cur_edition->getChapterbyTimecode( sys.i_pts );

    /* we have moved to a new chapter */
    if ( p_cur_chapter != NULL && p_current_chapter != p_cur_chapter )
        {
            msg_Dbg( &demux, "NEW CHAPTER %"PRId64, sys.i_pts );
            if ( p_cur_edition->b_ordered )
            {
                /* FIXME EnterAndLeave has probably been broken for a long time */
                // Leave/Enter up to the link point
                b_has_seeked = p_cur_chapter->EnterAndLeave( p_current_chapter );
                if ( !b_has_seeked )
                {
                    // only physically seek if necessary
                    if ( p_current_chapter == NULL ||
                        ( p_current_chapter->p_chapter->i_end_time != p_cur_chapter->p_chapter->i_start_time ) ||
                        ( p_current_chapter && p_current_chapter->p_segment != p_cur_chapter->p_segment ) )
                    {
                        /* hack : we have to use input to seek in order to clean buffers */
                        var_SetTime( demux.p_sys->p_input, "time", p_cur_chapter->i_virtual_start_time );
                        return true;
                    }
                }
            }

            p_current_chapter = p_cur_chapter;
            if ( p_cur_chapter->i_seekpoint_num > 0 )
            {
                demux.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
                demux.info.i_title = sys.i_current_title = i_sys_title;
                demux.info.i_seekpoint = p_cur_chapter->i_seekpoint_num - 1;
            }

            return b_has_seeked;
        }
        else if ( p_cur_chapter == NULL )
        {
            /* out of the scope of the data described by chapters, leave the edition */
            if ( p_cur_edition->b_ordered && p_current_chapter != NULL )
            {
                /* TODO */
                if ( !p_cur_edition->p_edition->EnterAndLeave( p_current_chapter->p_chapter, false ) )
                    p_current_chapter = NULL;
                else
                    return true;
            }
        }
    return false;
419
420
}

Denis Charmet's avatar
Denis Charmet committed
421
bool virtual_chapter_c::EnterAndLeave( virtual_chapter_c *p_item, bool b_enter )
422
{
Denis Charmet's avatar
Denis Charmet committed
423
424
    if( !p_chapter )
        return false;
425

Denis Charmet's avatar
Denis Charmet committed
426
    return p_chapter->EnterAndLeave( p_item->p_chapter, b_enter );
427
428
}

Denis Charmet's avatar
Denis Charmet committed
429
430
void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, 
                              virtual_chapter_c *p_chapter, int64_t i_global_position )
431
{
432
    demux_sys_t *p_sys = demuxer.p_sys;
433

Denis Charmet's avatar
Denis Charmet committed
434
435

    /* find the actual time for an ordered edition */
436
    if ( p_chapter == NULL )
Denis Charmet's avatar
Denis Charmet committed
437
438
        /* 1st, we need to know in which chapter we are */
        p_chapter = editions[ i_current_edition ]->getChapterbyTimecode( i_date );
439

440
    if ( p_chapter != NULL )
441
    {
Denis Charmet's avatar
Denis Charmet committed
442
443
444
        p_sys->i_chapter_time =
            i_time_offset = p_chapter->i_virtual_start_time - ( ( p_chapter->p_chapter )? p_chapter->p_chapter->i_start_time : 0 );
        if ( p_chapter->p_chapter && p_chapter->i_seekpoint_num > 0 )
445
        {
446
447
            demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
            demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
448
            demuxer.info.i_seekpoint = p_chapter->i_seekpoint_num - 1;
449
        }
Denis Charmet's avatar
Denis Charmet committed
450
451
452
453
454
455
456
457
458
459

        if( p_current_chapter->p_segment != p_chapter->p_segment )
        {
            p_current_chapter->p_segment->UnSelect();
            es_out_Control( demuxer.out, ES_OUT_RESET_PCR );
            p_chapter->p_segment->Select( i_date );
        }
        p_current_chapter = p_chapter;

        p_chapter->p_segment->Seek( i_date, i_time_offset, i_global_position );
460
    }
Denis Charmet's avatar
Denis Charmet committed
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
}

virtual_chapter_c * virtual_chapter_c::FindChapter( int64_t i_find_uid )
{
    if( p_chapter && ( p_chapter->i_uid == i_find_uid ) )
        return this;

    for( size_t i = 0; i < sub_chapters.size(); i++ )
    {
        virtual_chapter_c * p_res = sub_chapters[i]->FindChapter( i_find_uid );
        if( p_res )
            return p_res;
    }

    return NULL;
}

virtual_chapter_c * virtual_segment_c::FindChapter( int64_t i_find_uid )
{
    virtual_edition_c * p_edition = editions[i_current_edition];
481

Denis Charmet's avatar
Denis Charmet committed
482
    for( size_t i = 0; p_edition->chapters.size(); i++ )
483
    {
Denis Charmet's avatar
Denis Charmet committed
484
485
486
        virtual_chapter_c * p_chapter = p_edition->chapters[i]->FindChapter( i_find_uid );
        if( p_chapter )
            return p_chapter;
487
    }
Denis Charmet's avatar
Denis Charmet committed
488
489
    return NULL;
}
490

Denis Charmet's avatar
Denis Charmet committed
491
492
493
494
495
496
497
498
int virtual_chapter_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
{
    if ( p_chapter && ( !p_chapter->b_display_seekpoint || p_chapter->psz_name == "" ) )
    {
        p_chapter->psz_name = p_chapter->GetCodecName();
        if ( p_chapter->psz_name != "" )
            p_chapter->b_display_seekpoint = true;
    }
499

Denis Charmet's avatar
Denis Charmet committed
500
501
502
    if ( ( p_chapter && p_chapter->b_display_seekpoint &&
         ( ( sub_chapters.size() > 0 && i_virtual_start_time != sub_chapters[0]->i_virtual_start_time) ||
           sub_chapters.size() == 0 ) ) || !p_chapter )
503
    {
Denis Charmet's avatar
Denis Charmet committed
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
        seekpoint_t *sk = vlc_seekpoint_New();

        sk->i_time_offset = i_virtual_start_time;
        if( p_chapter )
            sk->psz_name = strdup( p_chapter->psz_name.c_str() );
        else
            sk->psz_name = strdup("dummy chapter");

        /* A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value. */
        title.i_seekpoint++;
        title.seekpoint = (seekpoint_t**)xrealloc( title.seekpoint,
                                 title.i_seekpoint * sizeof( seekpoint_t* ) );
        title.seekpoint[title.i_seekpoint-1] = sk;

        if ( (p_chapter && p_chapter->b_user_display ) ||  !p_chapter )
            i_user_chapters++;
520
    }
Denis Charmet's avatar
Denis Charmet committed
521
522
523
524
    i_seekpoint_num = i_user_chapters;

    for( size_t i = 0; i < sub_chapters.size(); i++ )
        sub_chapters[i]->PublishChapters( title, i_user_chapters, i_level + 1 );
525

Denis Charmet's avatar
Denis Charmet committed
526
    return i_user_chapters;
527
528
}

Denis Charmet's avatar
Denis Charmet committed
529
530

int virtual_edition_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
531
{
Denis Charmet's avatar
Denis Charmet committed
532
533
534

    /* HACK for now don't expose edition as a seekpoint if its start time is the same than it's first chapter */
    if( chapters.size() > 0 && chapters[0]->i_virtual_start_time )
535
    {
Denis Charmet's avatar
Denis Charmet committed
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
        seekpoint_t *sk = vlc_seekpoint_New();

        sk->i_time_offset = 0;
        if( p_edition )
            sk->psz_name = strdup( p_edition->psz_name.c_str() );
        else
            sk->psz_name = strdup( "Dummy edition" );

        title.i_seekpoint++;
        title.seekpoint = (seekpoint_t**)xrealloc( title.seekpoint,
                             title.i_seekpoint * sizeof( seekpoint_t* ) );
        title.seekpoint[title.i_seekpoint - 1] = sk;
        i_level++;

        i_user_chapters++;
        i_seekpoint_num = i_user_chapters;
552
    }
Denis Charmet's avatar
Denis Charmet committed
553
554
555
556
557

    for( size_t i = 0; i < chapters.size(); i++ )
        chapters[i]->PublishChapters( title, i_user_chapters, i_level );

    return i_user_chapters;
558
}
559

Denis Charmet's avatar
Denis Charmet committed
560
std::string virtual_edition_c::GetMainName()
561
{
Denis Charmet's avatar
Denis Charmet committed
562
563
564
565
566
    if( p_edition )
        return p_edition->GetMainName();

    return std::string("");
}
567

Denis Charmet's avatar
Denis Charmet committed
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
bool virtual_chapter_c::Enter( bool b_do_subs )
{
    if( p_chapter )
        return p_chapter->Enter( b_do_subs );
    return false;
}

bool virtual_chapter_c::Leave( bool b_do_subs )
{
    if( p_chapter )
        return p_chapter->Leave( b_do_subs );
    return false;
}

#if MKV_DEBUG
void virtual_chapter_c::print() 
{
    msg_Dbg( &p_segment->sys.demuxer, "*** chapter %"PRId64" - %"PRId64" (%u)",
             i_virtual_start_time, i_virtual_stop_time, sub_chapters.size() );
    for( size_t i = 0; i < sub_chapters.size(); i++ )
        sub_chapters[i]->print();
589
}
Denis Charmet's avatar
Denis Charmet committed
590
#endif