virtual_segment.cpp 24.6 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

27
#include "demux.hpp"
28

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

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

Denis Charmet's avatar
Denis Charmet committed
54
55
    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;
56

57
    if( p_chap->p_segment_uid &&
Denis Charmet's avatar
Denis Charmet committed
58
       ( !( p_segment = getSegmentbyUID( (KaxSegmentUID*) p_chap->p_segment_uid,segments ) ) || !b_ordered ) )
59
    {
Denis Charmet's avatar
Denis Charmet committed
60
61
62
63
        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;
64
    }
Denis Charmet's avatar
Denis Charmet committed
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

    /* 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,
91
             "Virtual chapter %s from %" PRId64 " to %" PRId64 " - " ,
92
             p_chap->psz_name.c_str(), p_vchap->i_virtual_start_time, p_vchap->i_virtual_stop_time );
Denis Charmet's avatar
Denis Charmet committed
93
94

    return p_vchap;
95
}
96

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


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

    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++ )
118
        {
Denis Charmet's avatar
Denis Charmet committed
119
120
121
122
123
124
            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 );
        }
125
126
127
128
        if( chapters.size() )
            i_duration = chapters[ chapters.size() - 1 ]->i_virtual_stop_time;
        else
            i_duration = 0; /* Empty ordered editions will be ignored */
Denis Charmet's avatar
Denis Charmet committed
129
130
131
132
133
134
135
136
    }
    else /* Not ordered or no edition at all */
    {
        matroska_segment_c * p_cur = p_main_segment;
        virtual_chapter_c * p_vchap = NULL;
        int64_t tmp = 0;

        /* check for prev linked segments */
137
138
        /* 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
139
140
141
        {
            matroska_segment_c * p_prev = NULL;
            if( ( p_prev = getSegmentbyUID( p_cur->p_prev_segment_uid, opened_segments ) ) )
142
            {
Denis Charmet's avatar
Denis Charmet committed
143
144
145
                tmp = 0;
                msg_Dbg( &p_main_segment->sys.demuxer, "Prev segment 0x%x found\n",
                         *(int32_t*)p_cur->p_prev_segment_uid->GetBuffer() );
146

147
148
149
150
                /* Preload segment */
                if ( !p_prev->b_preloaded )
                    p_prev->Preload();

Denis Charmet's avatar
Denis Charmet committed
151
152
153
154
155
156
157
                /* 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 );
158

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

        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 */
175
        for( int limit = 0; limit < 10 && p_cur->p_next_segment_uid; limit++ )
176
        {
Denis Charmet's avatar
Denis Charmet committed
177
178
            matroska_segment_c * p_next = NULL;
            if( ( p_next = getSegmentbyUID( p_cur->p_next_segment_uid, opened_segments ) ) )
179
            {
Denis Charmet's avatar
Denis Charmet committed
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() );

184
185
186
187
                /* Preload segment */
                if ( !p_next->b_preloaded )
                    p_next->Preload();

Denis Charmet's avatar
Denis Charmet committed
188
189
190
191
192
193
194
195
196
197
                /* 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;
198
                b_fake_ordered = true;
199
            }
Denis Charmet's avatar
Denis Charmet committed
200
201
            else /* segment not found */
                break;
202
        }
Denis Charmet's avatar
Denis Charmet committed
203
204
205

        /* Retime chapters */
        retimeChapters();
206
207
        if(b_fake_ordered)
            b_ordered = true;
208
    }
Denis Charmet's avatar
Denis Charmet committed
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

#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;

    /* 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 */
264
    size_t i;
Denis Charmet's avatar
Denis Charmet committed
265
266
267
268
269
    matroska_segment_c *p_segment = (*p_opened_segments)[0];
    i_current_edition = 0;
    i_sys_title = 0;
    p_current_chapter = NULL;

270
271
    i_current_edition = p_segment->i_default_edition;

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

277
        /* Ordered empty edition can happen when all chapters are
278
279
280
         * on an other segment which couldn't be found... ignore it */
        if(p_vedition->b_ordered && p_vedition->i_duration == 0)
        {
281

282
            msg_Warn( &p_segment->sys.demuxer,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
283
                      "Edition %s (%zu) links to other segments not found and is empty... ignoring it",
284
                       p_vedition->GetMainName().c_str(), i );
285
286
287
288
289
290
            if(i_current_edition == i)
            {
                msg_Warn( &p_segment->sys.demuxer,
                          "Empty edition was the default... defaulting to 0");
                i_current_edition = 0;
            }
291
292
293
294
            delete p_vedition;
        }
        else
            editions.push_back( p_vedition );
Denis Charmet's avatar
Denis Charmet committed
295
296
297
298
299
300
301
302
    }
    /*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 );
    }

303
304
305
306
307
308
309
310
    /* Get the default edition, if there is none, use the first one */
    for( i = 0; i < editions.size(); i++)
    {
        if( editions[i]->p_edition && editions[i]->p_edition->b_default )
        {
            i_current_edition = i;
            break;
        }
311
    }
Denis Charmet's avatar
Denis Charmet committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
    /* 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;
333
334
}

Denis Charmet's avatar
Denis Charmet committed
335
336

virtual_chapter_c * virtual_edition_c::BrowseCodecPrivate( unsigned int codec_id,
337
338
339
                                    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 )
340
{
Denis Charmet's avatar
Denis Charmet committed
341
342
343
344
    if( !p_edition )
        return NULL;

    for( size_t i = 0; i < chapters.size(); i++ )
345
    {
Denis Charmet's avatar
Denis Charmet committed
346
347
        virtual_chapter_c * p_result = chapters[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
        if( p_result )
348
349
350
            return p_result;
    }
    return NULL;
351
352
353
}


Denis Charmet's avatar
Denis Charmet committed
354
355
356
357
358

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 )
359
{
Denis Charmet's avatar
Denis Charmet committed
360
361
    if( !p_chapter )
        return NULL;
362

Denis Charmet's avatar
Denis Charmet committed
363
364
    if( p_chapter->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size ) )
        return this;
365

Denis Charmet's avatar
Denis Charmet committed
366
367
368
369
370
371
372
    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;
373
374
}

Denis Charmet's avatar
Denis Charmet committed
375
virtual_chapter_c* virtual_chapter_c::getSubChapterbyTimecode( int64_t time )
376
{
Denis Charmet's avatar
Denis Charmet committed
377
    for( size_t i = 0; i < sub_chapters.size(); i++ )
378
    {
Denis Charmet's avatar
Denis Charmet committed
379
380
        if( time >= sub_chapters[i]->i_virtual_start_time && time < sub_chapters[i]->i_virtual_stop_time )
            return sub_chapters[i]->getSubChapterbyTimecode( time );
381
    }
382

Denis Charmet's avatar
Denis Charmet committed
383
    return this;
384
385
}

Denis Charmet's avatar
Denis Charmet committed
386
virtual_chapter_c* virtual_edition_c::getChapterbyTimecode( int64_t time )
387
{
Denis Charmet's avatar
Denis Charmet committed
388
    for( size_t i = 0; i < chapters.size(); i++ )
389
    {
390
391
392
        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
393
            return chapters[i]->getSubChapterbyTimecode( time );
394
    }
Denis Charmet's avatar
Denis Charmet committed
395
396

    return NULL;
397
398
}

Denis Charmet's avatar
Denis Charmet committed
399
bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
400
{
Denis Charmet's avatar
Denis Charmet committed
401
402
403
404
405
406
407
408
409
410
411
    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 )
        {
412
            msg_Dbg( &demux, "NEW CHAPTER %" PRId64, sys.i_pts );
Denis Charmet's avatar
Denis Charmet committed
413
414
415
416
417
418
419
420
421
            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 ||
422
423
                        ( p_current_chapter && p_current_chapter->p_segment != p_cur_chapter->p_segment ) ||
                        ( p_current_chapter->p_chapter->i_end_time != p_cur_chapter->p_chapter->i_start_time ))
Denis Charmet's avatar
Denis Charmet committed
424
                    {
425
                        Seek( demux, p_cur_chapter->i_virtual_start_time, 0, p_cur_chapter, -1 );
Denis Charmet's avatar
Denis Charmet committed
426
427
428
                        return true;
                    }
                }
429
                sys.i_start_pts = p_cur_chapter->i_virtual_start_time;;
Denis Charmet's avatar
Denis Charmet committed
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
            }

            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;
455
456
}

Denis Charmet's avatar
Denis Charmet committed
457
bool virtual_chapter_c::EnterAndLeave( virtual_chapter_c *p_item, bool b_enter )
458
{
Denis Charmet's avatar
Denis Charmet committed
459
460
    if( !p_chapter )
        return false;
461

Denis Charmet's avatar
Denis Charmet committed
462
    return p_chapter->EnterAndLeave( p_item->p_chapter, b_enter );
463
464
}

465
void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset,
Denis Charmet's avatar
Denis Charmet committed
466
                              virtual_chapter_c *p_chapter, int64_t i_global_position )
467
{
468
    demux_sys_t *p_sys = demuxer.p_sys;
469

Denis Charmet's avatar
Denis Charmet committed
470
471

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

476
    if ( p_chapter != NULL )
477
    {
478
479
        i_time_offset = p_chapter->i_virtual_start_time - ( ( p_chapter->p_chapter )? p_chapter->p_chapter->i_start_time : 0 );
        p_sys->i_chapter_time = i_time_offset - p_chapter->p_segment->i_start_time;
Denis Charmet's avatar
Denis Charmet committed
480
        if ( p_chapter->p_chapter && p_chapter->i_seekpoint_num > 0 )
481
        {
482
483
            demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
            demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
484
            demuxer.info.i_seekpoint = p_chapter->i_seekpoint_num - 1;
485
        }
Denis Charmet's avatar
Denis Charmet committed
486
487

        if( p_current_chapter->p_segment != p_chapter->p_segment )
488
            ChangeSegment( p_current_chapter->p_segment, p_chapter->p_segment, i_date );
Denis Charmet's avatar
Denis Charmet committed
489
490
491
        p_current_chapter = p_chapter;

        p_chapter->p_segment->Seek( i_date, i_time_offset, i_global_position );
492
    }
Denis Charmet's avatar
Denis Charmet committed
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
}

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

Denis Charmet's avatar
Denis Charmet committed
514
    for( size_t i = 0; p_edition->chapters.size(); i++ )
515
    {
Denis Charmet's avatar
Denis Charmet committed
516
517
518
        virtual_chapter_c * p_chapter = p_edition->chapters[i]->FindChapter( i_find_uid );
        if( p_chapter )
            return p_chapter;
519
    }
Denis Charmet's avatar
Denis Charmet committed
520
521
    return NULL;
}
522

Denis Charmet's avatar
Denis Charmet committed
523
524
525
526
527
528
529
530
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;
    }
531

Denis Charmet's avatar
Denis Charmet committed
532
533
534
    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 )
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 = 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++;
552
    }
Denis Charmet's avatar
Denis Charmet committed
553
554
555
556
    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 );
557

Denis Charmet's avatar
Denis Charmet committed
558
    return i_user_chapters;
559
560
}

Denis Charmet's avatar
Denis Charmet committed
561
562

int virtual_edition_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
563
{
Denis Charmet's avatar
Denis Charmet committed
564
565

    /* HACK for now don't expose edition as a seekpoint if its start time is the same than it's first chapter */
566
567
    if( chapters.size() > 0 &&
        chapters[0]->i_virtual_start_time && p_edition )
568
    {
Denis Charmet's avatar
Denis Charmet committed
569
570
571
        seekpoint_t *sk = vlc_seekpoint_New();

        sk->i_time_offset = 0;
572
        sk->psz_name = strdup( p_edition->psz_name.c_str() );
Denis Charmet's avatar
Denis Charmet committed
573
574
575
576
577
578
579
580
581

        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;
582
    }
Denis Charmet's avatar
Denis Charmet committed
583

584
//    if( chapters.size() > 1 )
585
586
        for( size_t i = 0; i < chapters.size(); i++ )
            chapters[i]->PublishChapters( title, i_user_chapters, i_level );
Denis Charmet's avatar
Denis Charmet committed
587
588

    return i_user_chapters;
589
}
590

Denis Charmet's avatar
Denis Charmet committed
591
std::string virtual_edition_c::GetMainName()
592
{
Denis Charmet's avatar
Denis Charmet committed
593
594
595
596
597
    if( p_edition )
        return p_edition->GetMainName();

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

Denis Charmet's avatar
Denis Charmet committed
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
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
614
void virtual_chapter_c::print()
Denis Charmet's avatar
Denis Charmet committed
615
616
617
618
619
{
    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();
620
}
Denis Charmet's avatar
Denis Charmet committed
621
#endif
622
623
624
625

void virtual_segment_c::ChangeSegment( matroska_segment_c * p_old, matroska_segment_c * p_new, mtime_t i_start_time )
{
    size_t i, j;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
    char *sub_lang = NULL, *aud_lang = NULL;
    for( i = 0; i < p_old->tracks.size(); i++)
    {
        mkv_track_t *p_tk = p_old->tracks[i];
        es_format_t *p_ofmt = &p_tk->fmt;
        if( p_tk->p_es )
        {
            bool state = false;
            es_out_Control( p_old->sys.demuxer.out, ES_OUT_GET_ES_STATE, p_tk->p_es, &state );
            if( state )
            {
                if( p_ofmt->i_cat == AUDIO_ES )
                    aud_lang = p_tk->fmt.psz_language;
                else if( p_ofmt->i_cat == SPU_ES )
                    sub_lang = p_tk->fmt.psz_language;
            }
        }
    }
644
645
646
647
648
649
650
651
    for( i = 0; i < p_new->tracks.size(); i++)
    {
        mkv_track_t *p_tk = p_new->tracks[i];
        es_format_t *p_nfmt = &p_tk->fmt;

        /* Let's only do that for audio and video for now */
        if( p_nfmt->i_cat == AUDIO_ES || p_nfmt->i_cat == VIDEO_ES )
        {
652

653
654
655
656
657
658
659
660
661
662
663
664
665
            /* check for a similar elementary stream */
            for( j = 0; j < p_old->tracks.size(); j++)
            {
                es_format_t * p_ofmt = &p_old->tracks[j]->fmt;

                if( !p_old->tracks[j]->p_es )
                    continue;

                if( ( p_nfmt->i_cat == p_ofmt->i_cat ) &&
                    ( p_nfmt->i_codec == p_ofmt->i_codec ) &&
                    ( p_nfmt->i_priority == p_ofmt->i_priority ) &&
                    ( p_nfmt->i_bitrate == p_ofmt->i_bitrate ) &&
                    ( p_nfmt->i_extra == p_ofmt->i_extra ) &&
666
                    ( (!p_nfmt->p_extra && !p_ofmt->p_extra) ||
667
668
                      !memcmp( p_nfmt->p_extra, p_ofmt->p_extra, p_nfmt->i_extra ) ) &&
                    !strcasecmp( p_nfmt->psz_language, p_ofmt->psz_language ) &&
669
                    ( ( p_nfmt->i_cat == AUDIO_ES &&
670
                        !memcmp( &p_nfmt->audio, &p_ofmt->audio, sizeof(audio_format_t) ) ) ||
671
                      ( p_nfmt->i_cat == VIDEO_ES &&
672
673
674
                        !memcmp( &p_nfmt->video, &p_ofmt->video, sizeof(video_format_t) ) ) ) )
                {
                    /* FIXME handle video palettes... */
ivoire's avatar
ivoire committed
675
                    msg_Warn( &p_old->sys.demuxer, "Reusing decoder of old track %zu for track %zu", j, i);
676
677
678
679
680
681
                    p_tk->p_es = p_old->tracks[j]->p_es;
                    p_old->tracks[j]->p_es = NULL;
                    break;
                }
            }
        }
682
683
684
685
686
687
688
689
690
        p_tk->fmt.i_priority &= ~(0x10);
        if( ( sub_lang && p_nfmt->i_cat == SPU_ES && !strcasecmp(sub_lang, p_nfmt->psz_language) ) ||
            ( aud_lang && p_nfmt->i_cat == AUDIO_ES && !strcasecmp(aud_lang, p_nfmt->psz_language) ) )
        {
            msg_Warn( &p_old->sys.demuxer, "Since previous segment used lang %s forcing track %zu",
                      p_nfmt->psz_language, i);
            p_tk->fmt.i_priority |= 0x10;
            p_tk->b_forced = true;
        }
691
692
693
694
    }
    p_new->Select( i_start_time );
    p_old->UnSelect();
}