virtual_segment.cpp 20.3 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
    {
Denis Charmet's avatar
Denis Charmet committed
354 355
        if( time >= chapters[i]->i_virtual_start_time && time < chapters[i]->i_virtual_stop_time )
            return chapters[i]->getSubChapterbyTimecode( time );
356
    }
Denis Charmet's avatar
Denis Charmet committed
357 358

    return NULL;
359 360
}

Denis Charmet's avatar
Denis Charmet committed
361
bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
362
{
Denis Charmet's avatar
Denis Charmet committed
363 364 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
    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;
417 418
}

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

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

Denis Charmet's avatar
Denis Charmet committed
427 428
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 )
429
{
430
    demux_sys_t *p_sys = demuxer.p_sys;
431

Denis Charmet's avatar
Denis Charmet committed
432 433

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

438
    if ( p_chapter != NULL )
439
    {
Denis Charmet's avatar
Denis Charmet committed
440 441 442
        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 )
443
        {
444 445
            demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
            demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
446
            demuxer.info.i_seekpoint = p_chapter->i_seekpoint_num - 1;
447
        }
Denis Charmet's avatar
Denis Charmet committed
448 449 450 451 452 453 454 455 456 457

        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 );
458
    }
Denis Charmet's avatar
Denis Charmet committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
}

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];
479

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

Denis Charmet's avatar
Denis Charmet committed
489 490 491 492 493 494 495 496
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;
    }
497

Denis Charmet's avatar
Denis Charmet committed
498 499 500
    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 )
501
    {
Denis Charmet's avatar
Denis Charmet committed
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
        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++;
518
    }
Denis Charmet's avatar
Denis Charmet committed
519 520 521 522
    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 );
523

Denis Charmet's avatar
Denis Charmet committed
524
    return i_user_chapters;
525 526
}

Denis Charmet's avatar
Denis Charmet committed
527 528

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

    /* 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 )
533
    {
Denis Charmet's avatar
Denis Charmet committed
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
        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;
550
    }
Denis Charmet's avatar
Denis Charmet committed
551 552 553 554 555

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

    return i_user_chapters;
556
}
557

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

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

Denis Charmet's avatar
Denis Charmet committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
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();
587
}
Denis Charmet's avatar
Denis Charmet committed
588
#endif