]> git.sesse.net Git - vlc/blob - modules/demux/mkv/demux.cpp
MKV: rename functions to match better the actual implementation
[vlc] / modules / demux / mkv / demux.cpp
1
2 /*****************************************************************************
3  * mkv.cpp : matroska demuxer
4  *****************************************************************************
5  * Copyright (C) 2003-2004 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9  *          Steve Lhomme <steve.lhomme@free.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #include "demux.hpp"
27
28 #include "Ebml_parser.hpp"
29
30 event_thread_t::event_thread_t(demux_t *p_demux) : p_demux(p_demux)
31 {
32     vlc_mutex_init( &lock );
33     vlc_cond_init( &wait );
34     is_running = false;
35 }
36 event_thread_t::~event_thread_t()
37 {
38     ResetPci();
39     vlc_cond_destroy( &wait );
40     vlc_mutex_destroy( &lock );
41 }
42
43 void event_thread_t::SetPci(const pci_t *data)
44 {
45     vlc_mutex_locker l(&lock);
46
47     pci_packet = *data;
48
49 #ifndef WORDS_BIGENDIAN
50     for( uint8_t button = 1; button <= pci_packet.hli.hl_gi.btn_ns; button++) {
51         btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
52         binary *p_data = (binary*) button_ptr;
53
54         uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
55         uint16 i_x_end   = ((p_data[1] & 0x03) << 8 ) + p_data[2];
56         uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
57         uint16 i_y_end   = ((p_data[4] & 0x03) << 8 ) + p_data[5];
58         button_ptr->x_start = i_x_start;
59         button_ptr->x_end   = i_x_end;
60         button_ptr->y_start = i_y_start;
61         button_ptr->y_end   = i_y_end;
62
63     }
64     for ( uint8_t i = 0; i<3; i++ )
65         for ( uint8_t j = 0; j<2; j++ )
66             pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );
67 #endif
68     if( !is_running )
69     {
70         b_abort = false;
71         is_running = !vlc_clone( &thread, EventThread, this, VLC_THREAD_PRIORITY_LOW );
72     }
73 }
74 void event_thread_t::ResetPci()
75 {
76     if( !is_running )
77         return;
78
79     vlc_mutex_lock( &lock );
80     b_abort = true;
81     vlc_cond_signal( &wait );
82     vlc_mutex_unlock( &lock );
83
84     vlc_join( thread, NULL );
85     is_running = false;
86 }
87 int event_thread_t::EventMouse( vlc_object_t *p_this, char const *psz_var,
88                                 vlc_value_t oldval, vlc_value_t newval, void *p_data )
89 {
90     VLC_UNUSED( oldval ); VLC_UNUSED( newval );
91     event_thread_t *p_ev = (event_thread_t *) p_data;
92     vlc_mutex_lock( &p_ev->lock );
93     if( psz_var[6] == 'c' )
94     {
95         p_ev->b_clicked = true;
96         msg_Dbg( p_this, "Event Mouse: clicked");
97     }
98     else if( psz_var[6] == 'm' )
99         p_ev->b_moved = true;
100     vlc_cond_signal( &p_ev->wait );
101     vlc_mutex_unlock( &p_ev->lock );
102
103     return VLC_SUCCESS;
104 }
105
106 int event_thread_t::EventKey( vlc_object_t *p_this, char const *,
107                               vlc_value_t, vlc_value_t newval, void *p_data )
108 {
109     event_thread_t *p_ev = (event_thread_t *) p_data;
110     vlc_mutex_lock( &p_ev->lock );
111     p_ev->i_key_action = newval.i_int;
112     vlc_cond_signal( &p_ev->wait );
113     vlc_mutex_unlock( &p_ev->lock );
114     msg_Dbg( p_this, "Event Key");
115
116     return VLC_SUCCESS;
117 }
118
119 int event_thread_t::EventInput( vlc_object_t *p_this, char const *,
120                                 vlc_value_t, vlc_value_t newval, void *p_data )
121 {
122     VLC_UNUSED( p_this );
123     event_thread_t *p_ev = (event_thread_t *) p_data;
124     vlc_mutex_lock( &p_ev->lock );
125     if( newval.i_int == INPUT_EVENT_VOUT )
126     {
127         p_ev->b_vout |= true;
128         vlc_cond_signal( &p_ev->wait );
129     }
130     vlc_mutex_unlock( &p_ev->lock );
131
132     return VLC_SUCCESS;
133 }
134
135 void event_thread_t::EventThread()
136 {
137     demux_sys_t    *p_sys = p_demux->p_sys;
138     vlc_object_t   *p_vout = NULL;
139     int canc = vlc_savecancel ();
140
141     b_moved      = false;
142     b_clicked    = false;
143     i_key_action = 0;
144     b_vout       = true;
145
146     /* catch all key event */
147     var_AddCallback( p_demux->p_libvlc, "key-action", EventKey, this );
148     /* catch input event */
149     var_AddCallback( p_sys->p_input, "intf-event", EventInput, this );
150
151     /* main loop */
152     for( ;; )
153     {
154         vlc_mutex_lock( &lock );
155         while( !b_abort && !i_key_action && !b_moved && !b_clicked && !b_vout)
156             vlc_cond_wait( &wait, &lock );
157
158         if( b_abort )
159         {
160             vlc_mutex_unlock( &lock );
161             break;
162         }
163
164         /* KEY part */
165         if( i_key_action )
166         {
167             msg_Dbg( p_demux, "Handle Key Event");
168
169             pci_t *pci = &pci_packet;
170
171             uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
172
173             switch( i_key_action )
174             {
175             case ACTIONID_NAV_LEFT:
176                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
177                 {
178                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
179                     if ( p_button_ptr->left > 0 && p_button_ptr->left <= pci->hli.hl_gi.btn_ns )
180                     {
181                         i_curr_button = p_button_ptr->left;
182                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
183                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
184                         if ( button_ptr.auto_action_mode )
185                         {
186                             vlc_mutex_unlock( &lock );
187                             vlc_mutex_lock( &p_sys->lock_demuxer );
188
189                             // process the button action
190                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
191
192                             vlc_mutex_unlock( &p_sys->lock_demuxer );
193                             vlc_mutex_lock( &lock );
194                         }
195                     }
196                 }
197                 break;
198             case ACTIONID_NAV_RIGHT:
199                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
200                 {
201                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
202                     if ( p_button_ptr->right > 0 && p_button_ptr->right <= pci->hli.hl_gi.btn_ns )
203                     {
204                         i_curr_button = p_button_ptr->right;
205                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
206                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
207                         if ( button_ptr.auto_action_mode )
208                         {
209                             vlc_mutex_unlock( &lock );
210                             vlc_mutex_lock( &p_sys->lock_demuxer );
211
212                             // process the button action
213                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
214
215                             vlc_mutex_unlock( &p_sys->lock_demuxer );
216                             vlc_mutex_lock( &lock );
217                         }
218                     }
219                 }
220                 break;
221             case ACTIONID_NAV_UP:
222                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
223                 {
224                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
225                     if ( p_button_ptr->up > 0 && p_button_ptr->up <= pci->hli.hl_gi.btn_ns )
226                     {
227                         i_curr_button = p_button_ptr->up;
228                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
229                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
230                         if ( button_ptr.auto_action_mode )
231                         {
232                             vlc_mutex_unlock( &lock );
233                             vlc_mutex_lock( &p_sys->lock_demuxer );
234
235                             // process the button action
236                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
237
238                             vlc_mutex_unlock( &p_sys->lock_demuxer );
239                             vlc_mutex_lock( &lock );
240                         }
241                     }
242                 }
243                 break;
244             case ACTIONID_NAV_DOWN:
245                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
246                 {
247                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
248                     if ( p_button_ptr->down > 0 && p_button_ptr->down <= pci->hli.hl_gi.btn_ns )
249                     {
250                         i_curr_button = p_button_ptr->down;
251                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
252                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
253                         if ( button_ptr.auto_action_mode )
254                         {
255                             vlc_mutex_unlock( &lock );
256                             vlc_mutex_lock( &p_sys->lock_demuxer );
257
258                             // process the button action
259                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
260
261                             vlc_mutex_unlock( &p_sys->lock_demuxer );
262                             vlc_mutex_lock( &lock );
263                         }
264                     }
265                 }
266                 break;
267             case ACTIONID_NAV_ACTIVATE:
268                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
269                 {
270                     btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
271
272                     vlc_mutex_unlock( &lock );
273                     vlc_mutex_lock( &p_sys->lock_demuxer );
274
275                     // process the button action
276                     p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
277
278                     vlc_mutex_unlock( &p_sys->lock_demuxer );
279                     vlc_mutex_lock( &lock );
280                 }
281                 break;
282             default:
283                 break;
284             }
285             i_key_action = 0;
286         }
287
288         /* MOUSE part */
289         if( p_vout && ( b_moved || b_clicked ) )
290         {
291             int x, y;
292
293             var_GetCoords( p_vout, "mouse-moved", &x, &y );
294             pci_t *pci = &pci_packet;
295
296             if( b_clicked )
297             {
298                 int32_t button;
299                 int32_t best,dist,d;
300                 int32_t mx,my,dx,dy;
301
302                 msg_Dbg( p_demux, "Handle Mouse Event: Mouse clicked x(%d)*y(%d)", x, y);
303
304                 // get current button
305                 best = 0;
306                 dist = 0x08000000; /* >> than  (720*720)+(567*567); */
307                 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++)
308                 {
309                     btni_t *button_ptr = &(pci->hli.btnit[button-1]);
310
311                     if(((unsigned)x >= button_ptr->x_start)
312                      && ((unsigned)x <= button_ptr->x_end)
313                      && ((unsigned)y >= button_ptr->y_start)
314                      && ((unsigned)y <= button_ptr->y_end))
315                     {
316                         mx = (button_ptr->x_start + button_ptr->x_end)/2;
317                         my = (button_ptr->y_start + button_ptr->y_end)/2;
318                         dx = mx - x;
319                         dy = my - y;
320                         d = (dx*dx) + (dy*dy);
321                         /* If the mouse is within the button and the mouse is closer
322                         * to the center of this button then it is the best choice. */
323                         if(d < dist) {
324                             dist = d;
325                             best = button;
326                         }
327                     }
328                 }
329
330                 if ( best != 0)
331                 {
332                     btni_t button_ptr = pci->hli.btnit[best-1];
333                     uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
334
335                     msg_Dbg( &p_sys->demuxer, "Clicked button %d", best );
336                     vlc_mutex_unlock( &lock );
337                     vlc_mutex_lock( &p_sys->lock_demuxer );
338
339                     // process the button action
340                     p_sys->dvd_interpretor.SetSPRM( 0x88, best );
341                     p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
342
343                     msg_Dbg( &p_sys->demuxer, "Processed button %d", best );
344
345                     // select new button
346                     if ( best != i_curr_button )
347                     {
348                         vlc_value_t val;
349
350                         if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
351                         {
352                             vlc_mutex_t *p_mutex = (vlc_mutex_t *) val.p_address;
353                             uint32_t i_palette;
354
355                             if(button_ptr.btn_coln != 0) {
356                                 i_palette = pci->hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
357                             } else {
358                                 i_palette = 0;
359                             }
360
361                             for( int i = 0; i < 4; i++ )
362                             {
363                                 uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
364                                 uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
365                                 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
366
367                                 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
368                                 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
369                                 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
370                                 p_sys->palette[i][3] = i_alpha;
371                             }
372
373                             vlc_mutex_lock( p_mutex );
374                             val.i_int = button_ptr.x_start; var_Set( p_sys->p_input, "x-start", val );
375                             val.i_int = button_ptr.x_end;   var_Set( p_sys->p_input, "x-end",   val );
376                             val.i_int = button_ptr.y_start; var_Set( p_sys->p_input, "y-start", val );
377                             val.i_int = button_ptr.y_end;   var_Set( p_sys->p_input, "y-end",   val );
378
379                             val.p_address = (void *)p_sys->palette;
380                             var_Set( p_sys->p_input, "menu-palette", val );
381
382                             val.b_bool = true; var_Set( p_sys->p_input, "highlight", val );
383                             vlc_mutex_unlock( p_mutex );
384                         }
385                     }
386                     vlc_mutex_unlock( &p_sys->lock_demuxer );
387                     vlc_mutex_lock( &lock );
388                 }
389             }
390             else if( b_moved )
391             {
392 //                dvdnav_mouse_select( NULL, pci, x, y );
393             }
394
395             b_moved = false;
396             b_clicked = false;
397         }
398
399         b_vout = false;
400         vlc_mutex_unlock( &lock );
401
402         /* Always check vout */
403         if( p_vout && !vlc_object_alive (p_vout) )
404         {
405             var_DelCallback( p_vout, "mouse-moved", EventMouse, this );
406             var_DelCallback( p_vout, "mouse-clicked", EventMouse, this );
407             vlc_object_release( p_vout );
408             p_vout = NULL;
409         }
410
411         else if( p_vout == NULL )
412         {
413             p_vout = (vlc_object_t*) input_GetVout(p_sys->p_input);
414             if( p_vout)
415             {
416                 var_AddCallback( p_vout, "mouse-moved", EventMouse, this );
417                 var_AddCallback( p_vout, "mouse-clicked", EventMouse, this );
418             }
419         }
420     }
421
422     /* Release callback */
423     if( p_vout )
424     {
425         var_DelCallback( p_vout, "mouse-moved", EventMouse, this );
426         var_DelCallback( p_vout, "mouse-clicked", EventMouse, this );
427         vlc_object_release( p_vout );
428     }
429     var_DelCallback( p_sys->p_input, "intf-event", EventInput, this );
430     var_DelCallback( p_demux->p_libvlc, "key-action", EventKey, this );
431
432     vlc_restorecancel (canc);
433 }
434
435 void *event_thread_t::EventThread(void *data)
436 {
437     static_cast<event_thread_t*>(data)->EventThread();
438     return NULL;
439 }
440
441
442 demux_sys_t::~demux_sys_t()
443 {
444     CleanUi();
445     size_t i;
446     for ( i=0; i<streams.size(); i++ )
447         delete streams[i];
448     for ( i=0; i<opened_segments.size(); i++ )
449         delete opened_segments[i];
450     for ( i=0; i<used_segments.size(); i++ )
451         delete used_segments[i];
452     for ( i=0; i<stored_attachments.size(); i++ )
453         delete stored_attachments[i];
454     if( meta ) vlc_meta_Delete( meta );
455
456     while( titles.size() )
457     { vlc_input_title_Delete( titles.back() ); titles.pop_back();}
458
459     vlc_mutex_destroy( &lock_demuxer );
460 }
461
462
463 matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlStream *p_estream, bool b_initial )
464 {
465     int i_upper_lvl = 0;
466     EbmlElement *p_l0, *p_l1, *p_l2;
467     bool b_keep_stream = false, b_keep_segment;
468
469     // verify the EBML Header
470     p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL);
471     if (p_l0 == NULL)
472     {
473         msg_Err( p_demux, "No EBML header found" );
474         return NULL;
475     }
476
477     // verify we can read this Segment, we only support Matroska version 1 for now
478     p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
479
480     EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
481     if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
482     {
483         msg_Err( p_demux, "Not a Matroska file : DocType = %s ", std::string(doc_type).c_str());
484         return NULL;
485     }
486
487     EDocTypeReadVersion doc_read_version = GetChild<EDocTypeReadVersion>(*static_cast<EbmlHead*>(p_l0));
488     if (uint64(doc_read_version) > 2)
489     {
490         msg_Err( p_demux, "matroska file needs version %"PRId64" but only versions 1 & 2 supported", uint64(doc_read_version));
491         return NULL;
492     }
493
494     delete p_l0;
495
496
497     // find all segments in this file
498     p_l0 = p_estream->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFLL);
499     if (p_l0 == NULL)
500     {
501         return NULL;
502     }
503
504     matroska_stream_c *p_stream1 = new matroska_stream_c( *this );
505
506     while (p_l0 != 0)
507     {
508         if ( MKV_IS_ID( p_l0, KaxSegment) )
509         {
510             EbmlParser  *ep;
511             matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
512             b_keep_segment = b_initial;
513
514             ep = new EbmlParser(p_estream, p_l0, &demuxer );
515             p_segment1->ep = ep;
516             p_segment1->segment = (KaxSegment*)p_l0;
517
518             while ((p_l1 = ep->Get()))
519             {
520                 if (MKV_IS_ID(p_l1, KaxInfo))
521                 {
522                     // find the families of this segment
523                     KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
524
525                     p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
526                     for( size_t i = 0; i < p_info->ListSize(); i++ )
527                     {
528                         EbmlElement *l = (*p_info)[i];
529
530                         if( MKV_IS_ID( l, KaxSegmentUID ) )
531                         {
532                             KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
533                             b_keep_segment = (FindSegment( *p_uid ) == NULL);
534                             if ( !b_keep_segment )
535                                 break; // this segment is already known
536                             opened_segments.push_back( p_segment1 );
537                             delete p_segment1->p_segment_uid;
538                             p_segment1->p_segment_uid = new KaxSegmentUID(*p_uid);
539                         }
540                         else if( MKV_IS_ID( l, KaxPrevUID ) )
541                         {
542                             p_segment1->p_prev_segment_uid = new KaxPrevUID( *static_cast<KaxPrevUID*>(l) );
543                         }
544                         else if( MKV_IS_ID( l, KaxNextUID ) )
545                         {
546                             p_segment1->p_next_segment_uid = new KaxNextUID( *static_cast<KaxNextUID*>(l) );
547                         }
548                         else if( MKV_IS_ID( l, KaxSegmentFamily ) )
549                         {
550                             KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
551                             p_segment1->families.push_back( p_fam );
552                         }
553                     }
554                     break;
555                 }
556             }
557             if ( b_keep_segment )
558             {
559                 b_keep_stream = true;
560                 p_stream1->segments.push_back( p_segment1 );
561             }
562             else
563             {
564                 p_segment1->segment = NULL;
565                 delete p_segment1;
566             }
567         }
568         if (p_l0->IsFiniteSize() )
569         {
570             p_l0->SkipData(*p_estream, KaxMatroska_Context);
571             p_l0 = p_estream->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFL);
572         }
573         else
574         {
575             p_l0 = NULL;
576         }
577     }
578
579     if ( !b_keep_stream )
580     {
581         delete p_stream1;
582         p_stream1 = NULL;
583     }
584
585     return p_stream1;
586 }
587
588 void demux_sys_t::InitUi()
589 {
590     msg_Dbg( &demuxer, "Starting the UI Hook" );
591
592     /* FIXME hack hack hack hack FIXME */
593     /* Get p_input and create variable */
594     p_input = demux_GetParentInput( &demuxer );
595     var_Create( p_input, "x-start", VLC_VAR_INTEGER );
596     var_Create( p_input, "y-start", VLC_VAR_INTEGER );
597     var_Create( p_input, "x-end", VLC_VAR_INTEGER );
598     var_Create( p_input, "y-end", VLC_VAR_INTEGER );
599     var_Create( p_input, "color", VLC_VAR_ADDRESS );
600     var_Create( p_input, "menu-palette", VLC_VAR_ADDRESS );
601     var_Create( p_input, "highlight", VLC_VAR_BOOL );
602     var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
603
604     /* Now create our event thread catcher */
605     p_ev = new event_thread_t(&demuxer);
606 }
607
608 void demux_sys_t::CleanUi()
609 {
610     delete p_ev;
611     p_ev = NULL;
612
613     var_Destroy( p_input, "highlight-mutex" );
614     var_Destroy( p_input, "highlight" );
615     var_Destroy( p_input, "x-start" );
616     var_Destroy( p_input, "x-end" );
617     var_Destroy( p_input, "y-start" );
618     var_Destroy( p_input, "y-end" );
619     var_Destroy( p_input, "color" );
620     var_Destroy( p_input, "menu-palette" );
621
622     vlc_object_release( p_input );
623
624     msg_Dbg( &demuxer, "Stopping the UI Hook" );
625 }
626
627 void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
628 {
629     for (size_t i=0; i<opened_segments.size(); i++)
630     {
631         opened_segments[i]->PreloadFamily( of_segment );
632     }
633 }
634
635 // preload all the linked segments for all preloaded segments
636 void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
637 {
638     size_t i_preloaded, i, j;
639     virtual_segment_c *p_seg;
640
641     p_current_segment = VirtualFromSegments( p_segment );
642
643     used_segments.push_back( p_current_segment );
644
645     // create all the other virtual segments of the family
646     do {
647         i_preloaded = 0;
648         for ( i=0; i< opened_segments.size(); i++ )
649         {
650             if ( opened_segments[i]->b_preloaded && !IsUsedSegment( *opened_segments[i] ) )
651             {
652                 p_seg = VirtualFromSegments( opened_segments[i] );
653                 used_segments.push_back( p_seg );
654                 i_preloaded++;
655             }
656         }
657     } while ( i_preloaded ); // worst case: will stop when all segments are found as family related
658
659     // publish all editions of all usable segment
660     for ( i=0; i< used_segments.size(); i++ )
661     {
662         p_seg = used_segments[i];
663         if ( p_seg->Editions() != NULL )
664         {
665             input_title_t *p_title = vlc_input_title_New();
666             p_seg->i_sys_title = i;
667             int i_chapters;
668
669             // TODO use a name for each edition, let the TITLE deal with a codec name
670             for ( j=0; j<p_seg->Editions()->size(); j++ )
671             {
672                 if ( p_title->psz_name == NULL )
673                 {
674                     const char* psz_tmp = (*p_seg->Editions())[j]->GetMainName().c_str();
675                     if( *psz_tmp != '\0' )
676                         p_title->psz_name = strdup( psz_tmp );
677                 }
678
679                 chapter_edition_c *p_edition = (*p_seg->Editions())[j];
680
681                 i_chapters = 0;
682                 p_edition->PublishChapters( *p_title, i_chapters, 0 );
683             }
684
685             // create a name if there is none
686             if ( p_title->psz_name == NULL )
687             {
688                 if( asprintf(&(p_title->psz_name), "%s %d", N_("Segment"), (int)i) == -1 )
689                     p_title->psz_name = NULL;
690             }
691
692             titles.push_back( p_title );
693         }
694     }
695
696     // TODO decide which segment should be first used (VMG for DVD)
697 }
698
699 bool demux_sys_t::IsUsedSegment( matroska_segment_c &segment ) const
700 {
701     for ( size_t i=0; i< used_segments.size(); i++ )
702     {
703         if ( used_segments[i]->FindUID( *segment.p_segment_uid ) )
704             return true;
705     }
706     return false;
707 }
708
709 virtual_segment_c *demux_sys_t::VirtualFromSegments( matroska_segment_c *p_segment ) const
710 {
711     virtual_segment_c *p_result = new virtual_segment_c( p_segment );
712     p_result->AddSegments( opened_segments );
713
714     return p_result;
715 }
716
717 bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
718 {
719     if ( p_new_segment != NULL && p_new_segment != p_current_segment )
720     {
721         if ( p_current_segment != NULL && p_current_segment->CurrentSegment() != NULL )
722             p_current_segment->CurrentSegment()->UnSelect();
723
724         p_current_segment = p_new_segment;
725         i_current_title = p_new_segment->i_sys_title;
726     }
727     if( !p_current_segment->CurrentSegment()->b_cues )
728         msg_Warn( &p_current_segment->CurrentSegment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );
729
730     f_duration = p_current_segment->Duration();
731
732     /* add information */
733     p_current_segment->CurrentSegment()->InformationCreate( );
734     p_current_segment->CurrentSegment()->Select( 0 );
735
736     return true;
737 }
738
739 void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapter )
740 {
741     // if the segment is not part of the current segment, select the new one
742     if ( &vsegment != p_current_segment )
743     {
744         PreparePlayback( &vsegment );
745     }
746
747     if ( p_chapter != NULL )
748     {
749         if ( !p_chapter->Enter( true ) )
750         {
751             // jump to the location in the found segment
752             vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
753         }
754     }
755
756 }
757
758 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
759 {
760     for (size_t i=0; i<opened_segments.size(); i++)
761     {
762         if ( *opened_segments[i]->p_segment_uid == uid )
763             return opened_segments[i];
764     }
765     return NULL;
766 }
767
768 chapter_item_c *demux_sys_t::BrowseCodecPrivate( unsigned int codec_id,
769                                         bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ),
770                                         const void *p_cookie,
771                                         size_t i_cookie_size,
772                                         virtual_segment_c * &p_segment_found )
773 {
774     chapter_item_c *p_result = NULL;
775     for (size_t i=0; i<used_segments.size(); i++)
776     {
777         p_result = used_segments[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
778         if ( p_result != NULL )
779         {
780             p_segment_found = used_segments[i];
781             break;
782         }
783     }
784     return p_result;
785 }
786
787 chapter_item_c *demux_sys_t::FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found )
788 {
789     chapter_item_c *p_result = NULL;
790     for (size_t i=0; i<used_segments.size(); i++)
791     {
792         p_result = used_segments[i]->FindChapter( i_find_uid );
793         if ( p_result != NULL )
794         {
795             p_segment_found = used_segments[i];
796             break;
797         }
798     }
799     return p_result;
800 }
801
802