virtual_segment.cpp 26.8 KB
Newer Older
1
/*****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
2
 * virtual_segment.cpp : virtual segment implementation in the MKV demuxer
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright © 2003-2011 VideoLAN and VLC authors
5 6 7 8
 * $Id$
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.fr>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9
 *          Denis Charmet <typx@dinauz.org>
10
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
11 12 13
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
14 15 16 17
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
20
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
21 22 23
 * You should have received a copy of the GNU Lesser 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.
24
 *****************************************************************************/
Denis Charmet's avatar
Denis Charmet committed
25
#include <vector>
26
#include <new>
27

28
#include "demux.hpp"
29

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

virtual_chapter_c * virtual_chapter_c::CreateVirtualChapter( chapter_item_c * p_chap,
43
                                                             matroska_segment_c & main_segment,
44
                                                             std::vector<matroska_segment_c*> & segments,
45
                                                             int64_t & usertime_offset, bool b_ordered)
Denis Charmet's avatar
Denis Charmet committed
46
{
47
    std::vector<virtual_chapter_c *> sub_chapters;
Denis Charmet's avatar
Denis Charmet committed
48 49 50
    if( !p_chap )
    {
        /* Dummy chapter use the whole segment */
51
        return new (std::nothrow) virtual_chapter_c( main_segment, NULL, 0, main_segment.i_duration * 1000, sub_chapters );
Denis Charmet's avatar
Denis Charmet committed
52
    }
53

54
    matroska_segment_c * p_segment = &main_segment;
55
    if( p_chap->p_segment_uid &&
Denis Charmet's avatar
Denis Charmet committed
56
       ( !( p_segment = getSegmentbyUID( (KaxSegmentUID*) p_chap->p_segment_uid,segments ) ) || !b_ordered ) )
57
    {
58
        msg_Warn( &main_segment.sys.demuxer,
Denis Charmet's avatar
Denis Charmet committed
59 60 61
                  "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
    p_segment->Preload();
Denis Charmet's avatar
Denis Charmet committed
65

66
    int64_t start = ( b_ordered )? usertime_offset : p_chap->i_start_time;
67
    int64_t tmp = usertime_offset;
Denis Charmet's avatar
Denis Charmet committed
68 69 70

    for( size_t i = 0; i < p_chap->sub_chapters.size(); i++ )
    {
71
        virtual_chapter_c * p_vsubchap = CreateVirtualChapter( p_chap->sub_chapters[i], *p_segment, segments, tmp, b_ordered );
Denis Charmet's avatar
Denis Charmet committed
72 73

        if( p_vsubchap )
74 75
            sub_chapters.push_back( p_vsubchap );
    }
76 77 78 79 80
    int64_t stop = ( b_ordered )?
            (((p_chap->i_end_time == -1 ||
               (p_chap->i_end_time - p_chap->i_start_time) < (tmp - usertime_offset) )) ? tmp :
             p_chap->i_end_time - p_chap->i_start_time + usertime_offset )
            :p_chap->i_end_time;
81 82 83 84 85 86 87

    virtual_chapter_c * p_vchap = new (std::nothrow) virtual_chapter_c( *p_segment, p_chap, start, stop, sub_chapters );
    if( !p_vchap )
    {
        for( size_t i = 0 ; i < sub_chapters.size(); i++ )
            delete sub_chapters[i];
        return NULL;
Denis Charmet's avatar
Denis Charmet committed
88 89
    }

90 91
    if ( p_chap->i_end_time >= 0 )
        usertime_offset += p_chap->i_end_time - p_chap->i_start_time;
Denis Charmet's avatar
Denis Charmet committed
92
    else
93
        usertime_offset = tmp;
Denis Charmet's avatar
Denis Charmet committed
94

95
    msg_Dbg( &main_segment.sys.demuxer,
96
             "Virtual chapter %s from %" PRId64 " to %" PRId64 " - " ,
97
             p_chap->psz_name.c_str(), p_vchap->i_mk_virtual_start_time, p_vchap->i_mk_virtual_stop_time );
Denis Charmet's avatar
Denis Charmet committed
98 99

    return p_vchap;
100
}
101

Denis Charmet's avatar
Denis Charmet committed
102
virtual_chapter_c::~virtual_chapter_c()
103
{
104 105
    for( size_t i = 0 ; i < sub_vchapters.size(); i++ )
        delete sub_vchapters[i];
Denis Charmet's avatar
Denis Charmet committed
106
}
107 108


109
virtual_edition_c::virtual_edition_c( chapter_edition_c * p_edit, matroska_segment_c & main_segment, std::vector<matroska_segment_c*> & opened_segments)
Denis Charmet's avatar
Denis Charmet committed
110
{
111
    bool b_fake_ordered = false;
Denis Charmet's avatar
Denis Charmet committed
112
    p_edition = p_edit;
113
    b_ordered = false;
Denis Charmet's avatar
Denis Charmet committed
114 115 116 117 118 119 120 121

    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++ )
122
        {
Denis Charmet's avatar
Denis Charmet committed
123
            virtual_chapter_c * p_vchap = virtual_chapter_c::CreateVirtualChapter( p_edition->sub_chapters[i],
124
                                                                                   main_segment, opened_segments,
125
                                                                                   usertime_offset, b_ordered );
Denis Charmet's avatar
Denis Charmet committed
126
            if( p_vchap )
127
                vchapters.push_back( p_vchap );
Denis Charmet's avatar
Denis Charmet committed
128
        }
129 130
        if( vchapters.size() )
            i_duration = vchapters[ vchapters.size() - 1 ]->i_mk_virtual_stop_time;
131 132
        else
            i_duration = 0; /* Empty ordered editions will be ignored */
Denis Charmet's avatar
Denis Charmet committed
133 134 135
    }
    else /* Not ordered or no edition at all */
    {
136
        matroska_segment_c * p_cur = &main_segment;
Denis Charmet's avatar
Denis Charmet committed
137 138 139 140
        virtual_chapter_c * p_vchap = NULL;
        int64_t tmp = 0;

        /* check for prev linked segments */
141 142
        /* FIXME to avoid infinite recursion we limit to 10 prev should be better as parameter */
        for( int limit = 0; limit < 10 && p_cur->p_prev_segment_uid ; limit++ )
Denis Charmet's avatar
Denis Charmet committed
143 144 145
        {
            matroska_segment_c * p_prev = NULL;
            if( ( p_prev = getSegmentbyUID( p_cur->p_prev_segment_uid, opened_segments ) ) )
146
            {
Denis Charmet's avatar
Denis Charmet committed
147
                tmp = 0;
148
                msg_Dbg( &main_segment.sys.demuxer, "Prev segment 0x%x found\n",
Denis Charmet's avatar
Denis Charmet committed
149
                         *(int32_t*)p_cur->p_prev_segment_uid->GetBuffer() );
150

151
                p_prev->Preload();
152

Denis Charmet's avatar
Denis Charmet committed
153 154 155
                /* 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;

156
                p_vchap = virtual_chapter_c::CreateVirtualChapter( p_chap, *p_prev, opened_segments, tmp, b_ordered );
Denis Charmet's avatar
Denis Charmet committed
157 158

                if( p_vchap )
159
                    vchapters.insert( vchapters.begin(), p_vchap );
160

Denis Charmet's avatar
Denis Charmet committed
161
                p_cur = p_prev;
162
                b_fake_ordered = true;
Denis Charmet's avatar
Denis Charmet committed
163 164 165
            }
            else /* segment not found */
                break;
166
        }
Denis Charmet's avatar
Denis Charmet committed
167 168 169 170

        tmp = 0;

        /* Append the main segment */
171
        p_vchap = virtual_chapter_c::CreateVirtualChapter( (chapter_item_c*) p_edit, main_segment,
172
                                                           opened_segments, tmp, b_ordered );
Denis Charmet's avatar
Denis Charmet committed
173
        if( p_vchap )
174
            vchapters.push_back( p_vchap );
Denis Charmet's avatar
Denis Charmet committed
175 176

        /* Append next linked segments */
177
        for( int limit = 0; limit < 10 && p_cur->p_next_segment_uid; limit++ )
178
        {
Denis Charmet's avatar
Denis Charmet committed
179 180
            matroska_segment_c * p_next = NULL;
            if( ( p_next = getSegmentbyUID( p_cur->p_next_segment_uid, opened_segments ) ) )
181
            {
Denis Charmet's avatar
Denis Charmet committed
182
                tmp = 0;
183
                msg_Dbg( &main_segment.sys.demuxer, "Next segment 0x%x found\n",
Denis Charmet's avatar
Denis Charmet committed
184 185
                         *(int32_t*) p_cur->p_next_segment_uid->GetBuffer() );

186
                p_next->Preload();
187

Denis Charmet's avatar
Denis Charmet committed
188 189 190
                /* 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;

191
                 p_vchap = virtual_chapter_c::CreateVirtualChapter( p_chap, *p_next, opened_segments, tmp, b_ordered );
Denis Charmet's avatar
Denis Charmet committed
192 193

                if( p_vchap )
194
                    vchapters.push_back( p_vchap );
Denis Charmet's avatar
Denis Charmet committed
195 196

                p_cur = p_next;
197
                b_fake_ordered = true;
198
            }
Denis Charmet's avatar
Denis Charmet committed
199 200
            else /* segment not found */
                break;
201
        }
Denis Charmet's avatar
Denis Charmet committed
202 203 204

        /* Retime chapters */
        retimeChapters();
205 206
        if(b_fake_ordered)
            b_ordered = true;
207
    }
Denis Charmet's avatar
Denis Charmet committed
208

209
#ifdef MKV_DEBUG
210
    msg_Dbg( &p_main_segment.sys.demuxer, "-- RECAP-BEGIN --" );
Denis Charmet's avatar
Denis Charmet committed
211
    print();
212
    msg_Dbg( &p_main_segment.sys.demuxer, "-- RECAP-END --" );
Denis Charmet's avatar
Denis Charmet committed
213 214 215 216 217
#endif
}

virtual_edition_c::~virtual_edition_c()
{
218 219
    for( size_t i = 0; i < vchapters.size(); i++ )
        delete vchapters[i];
Denis Charmet's avatar
Denis Charmet committed
220 221 222 223
}

void virtual_edition_c::retimeSubChapters( virtual_chapter_c * p_vchap )
{
224
    mtime_t i_mk_stop_time = p_vchap->i_mk_virtual_stop_time;
225
    for( size_t i = p_vchap->sub_vchapters.size(); i-- > 0; )
Denis Charmet's avatar
Denis Charmet committed
226
    {
227
        virtual_chapter_c * p_vsubchap = p_vchap->sub_vchapters[i];
228
        //p_vsubchap->i_mk_virtual_start_time += p_vchap->i_mk_virtual_start_time;
Denis Charmet's avatar
Denis Charmet committed
229 230 231

        /*FIXME we artificially extend stop time if they were there before...*/
        /* Just for comfort*/
232 233
        p_vsubchap->i_mk_virtual_stop_time = i_mk_stop_time;
        i_mk_stop_time = p_vsubchap->i_mk_virtual_start_time;
Denis Charmet's avatar
Denis Charmet committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247

        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;

    /* On non ordered editions we have one top chapter == one segment */
248
    for( size_t i = 0; i < vchapters.size(); i++ )
Denis Charmet's avatar
Denis Charmet committed
249
    {
250
        virtual_chapter_c * p_vchap = vchapters[i];
Denis Charmet's avatar
Denis Charmet committed
251

252
        p_vchap->i_mk_virtual_start_time = i_duration;
253
        i_duration += p_vchap->segment.i_duration * 1000;
254
        p_vchap->i_mk_virtual_stop_time = i_duration;
Denis Charmet's avatar
Denis Charmet committed
255 256 257 258 259

        retimeSubChapters( p_vchap );
    }
}

260
virtual_segment_c::virtual_segment_c( matroska_segment_c & main_segment, std::vector<matroska_segment_c*> & p_opened_segments )
Denis Charmet's avatar
Denis Charmet committed
261 262
{
    /* Main segment */
263
    std::vector<chapter_edition_c*>::size_type i;
Denis Charmet's avatar
Denis Charmet committed
264
    i_sys_title = 0;
265 266
    p_current_vchapter = NULL;
    b_current_vchapter_entered = false;
Denis Charmet's avatar
Denis Charmet committed
267

268
    i_current_edition = main_segment.i_default_edition;
269

270
    for( i = 0; i < main_segment.stored_editions.size(); i++ )
Denis Charmet's avatar
Denis Charmet committed
271 272
    {
        /* Create a virtual edition from opened */
273
        virtual_edition_c * p_vedition = new virtual_edition_c( main_segment.stored_editions[i], main_segment, p_opened_segments );
Denis Charmet's avatar
Denis Charmet committed
274

275 276 277 278 279 280 281 282 283
        bool b_has_translate = false;
        for (size_t i=0; i < p_vedition->vchapters.size(); i++)
        {
            if ( p_vedition->vchapters[i]->segment.translations.size() != 0 )
            {
                b_has_translate = true;
                break;
            }
        }
284
        /* Ordered empty edition can happen when all chapters are
285
         * on an other segment which couldn't be found... ignore it */
286 287
        /* OK if it has chapters and the translate codec in Matroska */
        if(p_vedition->b_ordered && p_vedition->i_duration == 0 && !b_has_translate)
288
        {
289

290
            msg_Warn( &main_segment.sys.demuxer,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291
                      "Edition %s (%zu) links to other segments not found and is empty... ignoring it",
292
                       p_vedition->GetMainName().c_str(), i );
293 294
            if(i_current_edition == i)
            {
295
                msg_Warn( &main_segment.sys.demuxer,
296 297 298
                          "Empty edition was the default... defaulting to 0");
                i_current_edition = 0;
            }
299 300 301
            delete p_vedition;
        }
        else
302
            veditions.push_back( p_vedition );
Denis Charmet's avatar
Denis Charmet committed
303 304
    }
    /*if we don't have edition create a dummy one*/
305
    if( !main_segment.stored_editions.size() )
Denis Charmet's avatar
Denis Charmet committed
306
    {
307
        virtual_edition_c * p_vedition = new virtual_edition_c( NULL, main_segment, p_opened_segments );
308
        veditions.push_back( p_vedition );
Denis Charmet's avatar
Denis Charmet committed
309 310
    }

311
    /* Get the default edition, if there is none, use the first one */
312
    for( i = 0; i < veditions.size(); i++)
313
    {
314
        if( veditions[i]->p_edition && veditions[i]->p_edition->b_default )
315 316 317 318
        {
            i_current_edition = i;
            break;
        }
319
    }
Denis Charmet's avatar
Denis Charmet committed
320 321 322 323
}

virtual_segment_c::~virtual_segment_c()
{
324 325
    for( size_t i = 0; i < veditions.size(); i++ )
        delete veditions[i];
Denis Charmet's avatar
Denis Charmet committed
326 327 328 329 330 331 332 333 334 335 336 337
}

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;
338 339
}

Denis Charmet's avatar
Denis Charmet committed
340 341

virtual_chapter_c * virtual_edition_c::BrowseCodecPrivate( unsigned int codec_id,
342 343 344
                                    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 )
345
{
Denis Charmet's avatar
Denis Charmet committed
346 347 348
    if( !p_edition )
        return NULL;

349
    for( size_t i = 0; i < vchapters.size(); i++ )
350
    {
351
        virtual_chapter_c * p_result = vchapters[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
Denis Charmet's avatar
Denis Charmet committed
352
        if( p_result )
353 354 355
            return p_result;
    }
    return NULL;
356 357 358
}


Denis Charmet's avatar
Denis Charmet committed
359 360 361 362 363

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 )
364
{
Denis Charmet's avatar
Denis Charmet committed
365 366
    if( !p_chapter )
        return NULL;
367

Denis Charmet's avatar
Denis Charmet committed
368 369
    if( p_chapter->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size ) )
        return this;
370

371
    for( size_t i = 0; i < sub_vchapters.size(); i++ )
Denis Charmet's avatar
Denis Charmet committed
372
    {
373
        virtual_chapter_c * p_result = sub_vchapters[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
Denis Charmet's avatar
Denis Charmet committed
374 375 376 377
        if( p_result )
            return p_result;
    }
    return NULL;
378 379
}

380 381 382
bool virtual_chapter_c::ContainsTimestamp( int64_t time )
{
    /*with the current implementation only the last chapter can have a negative virtual_stop_time*/
383
    return ( time >= i_mk_virtual_start_time && time < i_mk_virtual_stop_time );
384 385
}

Denis Charmet's avatar
Denis Charmet committed
386
virtual_chapter_c* virtual_chapter_c::getSubChapterbyTimecode( int64_t time )
387
{
388
    for( size_t i = 0; i < sub_vchapters.size(); i++ )
389
    {
390
        if( sub_vchapters[i]->ContainsTimestamp( time ) )
391
            return sub_vchapters[i]->getSubChapterbyTimecode( time );
392
    }
393

Denis Charmet's avatar
Denis Charmet committed
394
    return this;
395 396
}

Denis Charmet's avatar
Denis Charmet committed
397
virtual_chapter_c* virtual_edition_c::getChapterbyTimecode( int64_t time )
398
{
399
    for( size_t i = 0; i < vchapters.size(); i++ )
400
    {
401
        if( vchapters[i]->ContainsTimestamp( time ) )
402
            return vchapters[i]->getSubChapterbyTimecode( time );
403
    }
Denis Charmet's avatar
Denis Charmet committed
404

405 406 407 408 409 410 411 412 413 414 415
    if( vchapters.size() )
    {
        virtual_chapter_c* last_chapter = vchapters.back();

        if( last_chapter->i_mk_virtual_start_time <= time &&
            last_chapter->i_mk_virtual_stop_time < 0 )
        {
            return last_chapter;
        }
    }

Denis Charmet's avatar
Denis Charmet committed
416
    return NULL;
417 418
}

Denis Charmet's avatar
Denis Charmet committed
419
bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
420
{
421
    demux_sys_t & sys = *(demux_sys_t *)demux.p_sys;
422 423
    virtual_chapter_c *p_cur_vchapter = NULL;
    virtual_edition_c *p_cur_vedition = veditions[ i_current_edition ];
Denis Charmet's avatar
Denis Charmet committed
424 425 426

    bool b_has_seeked = false;

427
    if ( !b_current_vchapter_entered && p_current_vchapter != NULL )
428
    {
429
        b_current_vchapter_entered = true;
430 431
        if (p_current_vchapter->Enter( true ))
            return true;
432 433
    }

434
    if ( sys.i_pts != VLC_TS_INVALID )
435 436 437 438 439 440
    {
        if ( p_current_vchapter != NULL && p_current_vchapter->ContainsTimestamp( sys.i_pts - VLC_TS_0 ))
            p_cur_vchapter = p_current_vchapter;
        else
            p_cur_vchapter = p_cur_vedition->getChapterbyTimecode( sys.i_pts - VLC_TS_0 );
    }
Denis Charmet's avatar
Denis Charmet committed
441 442

    /* we have moved to a new chapter */
443
    if ( p_cur_vchapter != NULL && p_current_vchapter != p_cur_vchapter )
Denis Charmet's avatar
Denis Charmet committed
444
        {
445
            msg_Dbg( &demux, "New Chapter %" PRId64 " uid=%" PRIu64, sys.i_pts - VLC_TS_0, p_cur_vchapter->p_chapter->i_uid );
446
            if ( p_cur_vedition->b_ordered )
Denis Charmet's avatar
Denis Charmet committed
447 448 449
            {
                /* FIXME EnterAndLeave has probably been broken for a long time */
                // Leave/Enter up to the link point
450
                b_has_seeked = p_cur_vchapter->EnterAndLeave( p_current_vchapter );
Denis Charmet's avatar
Denis Charmet committed
451 452 453
                if ( !b_has_seeked )
                {
                    // only physically seek if necessary
454 455 456
                    if ( p_current_vchapter == NULL ||
                        ( p_current_vchapter && &p_current_vchapter->segment != &p_cur_vchapter->segment ) ||
                        ( p_current_vchapter->p_chapter->i_end_time != p_cur_vchapter->p_chapter->i_start_time ))
Denis Charmet's avatar
Denis Charmet committed
457
                    {
458 459
                        /* Forcing reset pcr */
                        es_out_Control( demux.out, ES_OUT_RESET_PCR);
460
                        Seek( demux, p_cur_vchapter->i_mk_virtual_start_time, p_cur_vchapter );
Denis Charmet's avatar
Denis Charmet committed
461 462
                        return true;
                    }
463
                    sys.i_start_pts = p_cur_vchapter->i_mk_virtual_start_time + VLC_TS_0;
Denis Charmet's avatar
Denis Charmet committed
464 465 466
                }
            }

467 468
            p_current_vchapter = p_cur_vchapter;
            if ( p_cur_vchapter->i_seekpoint_num > 0 )
Denis Charmet's avatar
Denis Charmet committed
469
            {
470
                sys.i_updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
471 472
                sys.i_current_title = i_sys_title;
                sys.i_current_seekpoint = p_cur_vchapter->i_seekpoint_num - 1;
Denis Charmet's avatar
Denis Charmet committed
473 474 475 476
            }

            return b_has_seeked;
        }
477
        else if ( p_cur_vchapter == NULL )
Denis Charmet's avatar
Denis Charmet committed
478 479
        {
            /* out of the scope of the data described by chapters, leave the edition */
480
            if ( p_cur_vedition->b_ordered && p_current_vchapter != NULL )
Denis Charmet's avatar
Denis Charmet committed
481
            {
482
                if ( !p_current_vchapter->Leave( ) )
483
                {
484 485
                    p_current_vchapter = NULL;
                    b_current_vchapter_entered = false;
486
                }
Denis Charmet's avatar
Denis Charmet committed
487 488 489 490 491
                else
                    return true;
            }
        }
    return false;
492 493
}

494 495 496 497 498 499 500 501
bool virtual_chapter_c::Leave( )
{
    if( !p_chapter )
        return false;

    return p_chapter->Leave( true );
}

502
bool virtual_chapter_c::EnterAndLeave( virtual_chapter_c *p_leaving_vchapter, bool b_enter )
503
{
Denis Charmet's avatar
Denis Charmet committed
504 505
    if( !p_chapter )
        return false;
506

507
    return p_chapter->EnterAndLeave( p_leaving_vchapter->p_chapter, b_enter );
508 509
}

510
bool virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_mk_date,
511
                              virtual_chapter_c *p_vchapter, bool b_precise )
512
{
513
    demux_sys_t *p_sys = (demux_sys_t *)demuxer.p_sys;
514

Denis Charmet's avatar
Denis Charmet committed
515 516

    /* find the actual time for an ordered edition */
517
    if ( p_vchapter == NULL )
Denis Charmet's avatar
Denis Charmet committed
518
        /* 1st, we need to know in which chapter we are */
519
        p_vchapter = veditions[ i_current_edition ]->getChapterbyTimecode( i_mk_date );
520

521
    if ( p_vchapter != NULL )
522
    {
523 524 525
        mtime_t i_mk_time_offset = p_vchapter->i_mk_virtual_start_time - ( ( p_vchapter->p_chapter )? p_vchapter->p_chapter->i_start_time : 0 );
        p_sys->i_mk_chapter_time = i_mk_time_offset - p_vchapter->segment.i_mk_start_time /* + VLC_TS_0 */;
        if ( p_vchapter->p_chapter && p_vchapter->i_seekpoint_num > 0 )
526
        {
527
            p_sys->i_updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
528 529
            p_sys->i_current_title = i_sys_title;
            p_sys->i_current_seekpoint = p_vchapter->i_seekpoint_num - 1;
530
        }
Denis Charmet's avatar
Denis Charmet committed
531

532
        if( p_current_vchapter == NULL || &p_current_vchapter->segment != &p_vchapter->segment )
533
        {
534 535 536
            if ( p_current_vchapter )
            {
                KeepTrackSelection( p_current_vchapter->segment, p_vchapter->segment );
537
                p_current_vchapter->segment.ESDestroy();
538 539 540 541
            }
            msg_Dbg( &demuxer, "SWITCH CHAPTER uid=%" PRId64, p_vchapter->p_chapter ? p_vchapter->p_chapter->i_uid : 0 );
            p_current_vchapter = p_vchapter;
            p_sys->PreparePlayback( *this, i_mk_date );
542
            return true;
543 544 545
        }
        else
        {
546
            typedef bool( matroska_segment_c::* seek_callback_t )( demux_t &, mtime_t, mtime_t );
547 548 549 550 551 552

            seek_callback_t pf_seek = &matroska_segment_c::Seek;

            if( ! b_precise )
                pf_seek = &matroska_segment_c::FastSeek;

553
            p_current_vchapter = p_vchapter;
554

555
            return ( p_current_vchapter->segment.*pf_seek )( demuxer, i_mk_date, i_mk_time_offset );
556
        }
557
    }
558
    return false;
Denis Charmet's avatar
Denis Charmet committed
559 560 561 562 563 564 565
}

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

566
    for( size_t i = 0; i < sub_vchapters.size(); i++ )
Denis Charmet's avatar
Denis Charmet committed
567
    {
568
        virtual_chapter_c * p_res = sub_vchapters[i]->FindChapter( i_find_uid );
Denis Charmet's avatar
Denis Charmet committed
569 570 571 572 573 574 575 576 577
        if( p_res )
            return p_res;
    }

    return NULL;
}

virtual_chapter_c * virtual_segment_c::FindChapter( int64_t i_find_uid )
{
578
    virtual_edition_c * p_edition = veditions[i_current_edition];
579

Steve Lhomme's avatar
Steve Lhomme committed
580
    for( size_t i = 0; i < p_edition->vchapters.size(); i++ )
581
    {
582
        virtual_chapter_c * p_chapter = p_edition->vchapters[i]->FindChapter( i_find_uid );
Denis Charmet's avatar
Denis Charmet committed
583 584
        if( p_chapter )
            return p_chapter;
585
    }
Denis Charmet's avatar
Denis Charmet committed
586 587
    return NULL;
}
588

Denis Charmet's avatar
Denis Charmet committed
589 590 591 592 593 594 595 596
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;
    }
597

598
    if ( p_chapter && p_chapter->b_display_seekpoint )
599
    {
600 601 602
        if( p_chapter->b_user_display )
        {
            seekpoint_t *sk = vlc_seekpoint_New();
Denis Charmet's avatar
Denis Charmet committed
603

604
            sk->i_time_offset = i_mk_virtual_start_time;
Denis Charmet's avatar
Denis Charmet committed
605 606
            sk->psz_name = strdup( p_chapter->psz_name.c_str() );

607 608 609 610 611
            /* 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;
Denis Charmet's avatar
Denis Charmet committed
612 613

            i_user_chapters++;
614
        }
615
    }
Denis Charmet's avatar
Denis Charmet committed
616 617
    i_seekpoint_num = i_user_chapters;

618 619
    for( size_t i = 0; i < sub_vchapters.size(); i++ )
        sub_vchapters[i]->PublishChapters( title, i_user_chapters, i_level + 1 );
620

Denis Charmet's avatar
Denis Charmet committed
621
    return i_user_chapters;
622 623
}

Denis Charmet's avatar
Denis Charmet committed
624 625

int virtual_edition_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
626
{
Denis Charmet's avatar
Denis Charmet committed
627 628

    /* HACK for now don't expose edition as a seekpoint if its start time is the same than it's first chapter */
629 630
    if( vchapters.size() > 0 &&
        vchapters[0]->i_mk_virtual_start_time && p_edition )
631
    {
Denis Charmet's avatar
Denis Charmet committed
632 633
        seekpoint_t *sk = vlc_seekpoint_New();
        sk->i_time_offset = 0;
634
        sk->psz_name = strdup( p_edition->psz_name.c_str() );
Denis Charmet's avatar
Denis Charmet committed
635 636

        title.i_seekpoint++;
637 638
        title.seekpoint = static_cast<seekpoint_t**>( xrealloc( title.seekpoint,
                             title.i_seekpoint * sizeof( seekpoint_t* ) ) );
Denis Charmet's avatar
Denis Charmet committed
639 640 641 642 643
        title.seekpoint[title.i_seekpoint - 1] = sk;
        i_level++;

        i_user_chapters++;
        i_seekpoint_num = i_user_chapters;
644
    }
Denis Charmet's avatar
Denis Charmet committed
645

646
//    if( chapters.size() > 1 )
647 648
        for( size_t i = 0; i < vchapters.size(); i++ )
            vchapters[i]->PublishChapters( title, i_user_chapters, i_level );
Denis Charmet's avatar
Denis Charmet committed
649 650

    return i_user_chapters;
651
}
652

Denis Charmet's avatar
Denis Charmet committed
653
std::string virtual_edition_c::GetMainName()
654
{
Denis Charmet's avatar
Denis Charmet committed
655 656 657 658 659
    if( p_edition )
        return p_edition->GetMainName();

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

Denis Charmet's avatar
Denis Charmet committed
661 662 663 664 665 666 667 668 669 670 671 672 673 674
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;
}

675
#ifdef MKV_DEBUG
676
void virtual_chapter_c::print()
Denis Charmet's avatar
Denis Charmet committed
677
{
678
    msg_Dbg( &p_segment->sys.demuxer, "*** chapter %" PRId64 " - %" PRId64 " (%u)",
679
             i_mk_virtual_start_time, i_mk_virtual_stop_time, sub_chapters.size() );
Denis Charmet's avatar
Denis Charmet committed
680 681
    for( size_t i = 0; i < sub_chapters.size(); i++ )
        sub_chapters[i]->print();
682
}
Denis Charmet's avatar
Denis Charmet committed
683
#endif
684

685
void virtual_segment_c::KeepTrackSelection( matroska_segment_c & old, matroska_segment_c & next )
686
{
687 688
    typedef matroska_segment_c::tracks_map_t tracks_map_t;

689
    char *sub_lang = NULL, *aud_lang = NULL;
690
    for( tracks_map_t::iterator it = old.tracks.begin(); it != old.tracks.end(); ++it )
691
    {
692
        mkv_track_t &track = *it->second;
693
        if( track.p_es )
694 695
        {
            bool state = false;
696
            es_out_Control( old.sys.demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &state );
697 698
            if( state )
            {
699 700 701 702
                if( track.fmt.i_cat == AUDIO_ES )
                    aud_lang = track.fmt.psz_language;
                else if( track.fmt.i_cat == SPU_ES )
                    sub_lang = track.fmt.psz_language;
703 704 705
            }
        }
    }
706
    for( tracks_map_t::iterator it = next.tracks.begin(); it != next.tracks.end(); ++it )
707
    {
708 709
        mkv_track_t & new_track = *it->second;
        es_format_t & new_fmt   = new_track.fmt;
710 711

        /* Let's only do that for audio and video for now */
712
        if( new_fmt.i_cat == AUDIO_ES || new_fmt.i_cat == VIDEO_ES )
713 714
        {
            /* check for a similar elementary stream */
715
            for( tracks_map_t::iterator old_it = old.tracks.begin(); old_it != old.tracks.end(); ++old_it )
716
            {
717
                mkv_track_t& old_track = *old_it->second;
718
                es_format_t& old_fmt = old_track.fmt;
719

720
                if( !old_track.p_es )
721 722
                    continue;

723 724 725 726 727 728 729 730 731 732 733 734
                if( ( new_fmt.i_cat == old_fmt.i_cat ) &&
                    ( new_fmt.i_codec == old_fmt.i_codec ) &&
                    ( new_fmt.i_priority == old_fmt.i_priority ) &&
                    ( new_fmt.i_bitrate == old_fmt.i_bitrate ) &&
                    ( new_fmt.i_extra == old_fmt.i_extra ) &&
                    ( new_fmt.i_extra == 0 ||
                      !memcmp( new_fmt.p_extra, old_fmt.p_extra, new_fmt.i_extra ) ) &&
                    !strcasecmp( new_fmt.psz_language, old_fmt.psz_language ) &&
                    ( ( new_fmt.i_cat == AUDIO_ES &&
                        !memcmp( &new_fmt.audio, &old_fmt.audio, sizeof(audio_format_t) ) ) ||
                      ( new_fmt.i_cat == VIDEO_ES &&
                        !memcmp( &new_fmt.video, &old_fmt.video, sizeof(video_format_t) ) ) ) )
735 736
                {
                    /* FIXME handle video palettes... */
737 738 739
                    msg_Warn( &old.sys.demuxer, "Reusing decoder of old track %u for track %u", old_track.i_number, new_track.i_number);
                    new_track.p_es = old_track.p_es;
                    old_track.p_es = NULL;
740 741 742 743
                    break;
                }
            }
        }
744 745 746
        new_track.fmt.i_priority &= ~(0x10);
        if( ( sub_lang && new_fmt.i_cat == SPU_ES && !strcasecmp(sub_lang, new_fmt.psz_language) ) ||
            ( aud_lang && new_fmt.i_cat == AUDIO_ES && !strcasecmp(aud_lang, new_fmt.psz_language) ) )
747
        {
748 749 750 751
            msg_Warn( &old.sys.demuxer, "Since previous segment used lang %s forcing track %u",
                      new_fmt.psz_language, new_track.i_number );
            new_fmt.i_priority |= 0x10;
            new_track.b_forced = true;
752
        }
753 754
    }
}