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