]> git.sesse.net Git - vlc/blob - modules/gui/beos/VlcWrapper.cpp
1f7ac5e9d789c6806f7a4104234c58fa99fc2f7a
[vlc] / modules / gui / beos / VlcWrapper.cpp
1 /*****************************************************************************
2  * VlcWrapper.cpp: BeOS plugin for vlc (derived from MacOS X port)
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: VlcWrapper.cpp,v 1.31 2003/05/30 17:30:54 titer Exp $
6  *
7  * Authors: Florian G. Pflug <fgp@phlo.org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Tony Casltey <tony@castley.net>
10  *          Stephan Aßmus <stippi@yellowbites.com>
11  *          Eric Petit <titer@videolan.org>
12  *
13  * This program is free software{} you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation{} either version 2 of the License, or
16  * (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY{} without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program{} if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27 #include <AppKit.h>
28 #include <InterfaceKit.h>
29 #include <SupportKit.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/intf.h>
33 #include <vlc/vout.h>
34 extern "C"
35 {
36   #include <input_ext-plugins.h> // needed here when compiling without plugins
37   #include <audio_output.h>
38   #include <aout_internal.h>
39 }
40
41 #include "VlcWrapper.h"
42 #include "MsgVals.h"
43
44 const char * _AddEllipsis( char * string )
45 {
46     char * temp;
47     temp = (char*) calloc( strlen( string ) + 4, 1 );
48     sprintf( temp, "%s%s", string, B_UTF8_ELLIPSIS );
49     return temp;
50 }
51
52 /* constructor */
53 VlcWrapper::VlcWrapper( intf_thread_t *p_interface )
54 {
55     p_intf = p_interface;
56     p_input = NULL;
57     p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
58                                                 FIND_ANYWHERE );
59 }
60
61 /* destructor */
62 VlcWrapper::~VlcWrapper()
63 {
64     if( p_input )
65         vlc_object_release( p_input );
66
67     if( p_playlist )
68         vlc_object_release( p_playlist );
69 }
70
71 /* UpdateInput: updates p_input */
72 void VlcWrapper::UpdateInput()
73 {
74     if( !p_input )
75         p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
76                                                      FIND_ANYWHERE );
77         
78     if( p_input )
79         if( p_input->b_dead )
80         {
81             vlc_object_release( p_input );
82             p_input = NULL;
83         }
84 }
85
86
87 /***************************
88  * input infos and control *
89  ***************************/
90
91 bool VlcWrapper::HasInput()
92 {
93     return ( p_input != NULL );
94 }
95
96 int VlcWrapper::InputStatus()
97 {
98     if( !p_input )
99         return UNDEF_S;
100     
101     return p_input->stream.control.i_status;
102 }
103
104 int VlcWrapper::InputRate()
105 {
106     if( !p_input )
107         return DEFAULT_RATE;
108     
109     return p_input->stream.control.i_rate;
110 }
111
112 void VlcWrapper::InputSetRate( int rate )
113 {
114     if( !p_input )
115         return;
116
117     int times = 0;
118     int oldrate = InputRate();
119     switch( ( rate > oldrate ) ? ( rate / oldrate ) : ( oldrate / rate ) )
120     {
121         case 64:
122             times = 6;
123             break;
124         case 32:
125             times = 5;
126             break;
127         case 16:
128             times = 4;
129             break;
130         case 8:
131             times = 3;
132             break;
133         case 4:
134             times = 2;
135             break;
136         case 2:
137             times = 1;
138             break;
139     }
140
141     int newrate = oldrate;
142     for( int i = 0; i < times; i++ )
143     {
144         if( rate > oldrate )
145         {
146             input_SetStatus( p_input, INPUT_STATUS_SLOWER );
147             newrate *= 2;
148         }
149         else
150         {
151             input_SetStatus( p_input, INPUT_STATUS_FASTER );
152             newrate /= 2;
153         }
154         /* Wait it's actually done */
155         while( InputRate() != newrate )
156             msleep( 10000 );
157     }
158 }
159
160 BList * VlcWrapper::GetChannels( int i_cat )
161 {
162     if( p_input )
163     {
164         unsigned int i;
165         uint32 what;
166         const char* fieldName;
167
168         switch( i_cat )
169         {
170             case AUDIO_ES:
171             {
172                 what = SELECT_CHANNEL;
173                 fieldName = "channel";
174                 break;
175             }
176             case SPU_ES:
177             {
178                 what = SELECT_SUBTITLE;
179                 fieldName = "subtitle";
180                 break;
181             }
182             default:
183             return NULL;
184        }
185
186         vlc_mutex_lock( &p_input->stream.stream_lock );
187       
188         /* find which track is currently playing */
189         es_descriptor_t *p_es = NULL;
190         for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
191         {
192             if( p_input->stream.pp_selected_es[i]->i_cat == i_cat )
193                 p_es = p_input->stream.pp_selected_es[i];
194         }
195         
196         /* build a list of all tracks */
197         BList *list = new BList( p_input->stream.i_es_number );
198         BMenuItem *menuItem;
199         BMessage *message;
200         char *trackName;
201         
202         /* "None" */
203         message = new BMessage( what );
204         message->AddInt32( fieldName, -1 );
205         menuItem = new BMenuItem( _("None"), message );
206         if( !p_es )
207             menuItem->SetMarked( true );
208         list->AddItem( menuItem );
209         
210         for( i = 0; i < p_input->stream.i_es_number; i++ )
211         {
212             if( p_input->stream.pp_es[i]->i_cat == i_cat )
213             {
214                 message = new BMessage( what );
215                 message->AddInt32( fieldName, i );
216                 if( !p_input->stream.pp_es[i]->psz_desc ||
217                     !*p_input->stream.pp_es[i]->psz_desc )
218                     trackName = _("<unknown>");
219                 else
220                     trackName = strdup( p_input->stream.pp_es[i]->psz_desc );
221                 menuItem = new BMenuItem( trackName, message );
222                 if( p_input->stream.pp_es[i] == p_es )
223                     menuItem->SetMarked( true );
224                 list->AddItem( menuItem );
225             }
226         }
227         
228         vlc_mutex_unlock( &p_input->stream.stream_lock );
229
230         return list;
231     }
232     return NULL;
233 }
234
235 void VlcWrapper::ToggleLanguage( int i_language )
236 {
237     es_descriptor_t * p_es = NULL;
238     es_descriptor_t * p_es_old = NULL;
239
240     vlc_mutex_lock( &p_input->stream.stream_lock );
241     for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
242     {
243         if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
244         {
245             p_es_old = p_input->stream.pp_selected_es[i];
246             break;
247         }
248     }
249     vlc_mutex_unlock( &p_input->stream.stream_lock );
250     
251     if( i_language != -1 )
252     {
253         p_es = p_input->stream.pp_es[i_language];
254     }
255     if( p_es == p_es_old )
256     {
257         return;
258     }
259     if( p_es_old )
260     {
261         input_ToggleES( p_input, p_es_old, VLC_FALSE );
262     }
263     if( p_es )
264     {
265         input_ToggleES( p_input, p_es, VLC_TRUE );
266     }
267 }
268
269 void VlcWrapper::ToggleSubtitle( int i_subtitle )
270 {
271     es_descriptor_t * p_es = NULL;
272     es_descriptor_t * p_es_old = NULL;
273
274     vlc_mutex_lock( &p_input->stream.stream_lock );
275     for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
276     {
277         if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
278         {
279             p_es_old = p_input->stream.pp_selected_es[i];
280             break;
281         }
282     }
283     vlc_mutex_unlock( &p_input->stream.stream_lock );
284     
285     if( i_subtitle != -1 )
286     {
287         p_es = p_input->stream.pp_es[i_subtitle];
288     }
289     if( p_es == p_es_old )
290     {
291         return;
292     }
293     if( p_es_old )
294     {
295         input_ToggleES( p_input, p_es_old, VLC_FALSE );
296     }
297     if( p_es )
298     {
299         input_ToggleES( p_input, p_es, VLC_TRUE );
300     }
301 }
302
303 const char * VlcWrapper::GetTimeAsString()
304 {
305     static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
306         
307     if( p_input == NULL )
308     {
309         return ("-:--:--");
310     }     
311    
312     input_OffsetToTime( p_input, 
313                         psz_currenttime, 
314                         p_input->stream.p_selected_area->i_tell );        
315
316     return(psz_currenttime);
317 }
318
319 float VlcWrapper::GetTimeAsFloat()
320 {
321     float f_time = 0.0;
322
323     if( p_input != NULL )
324     {
325         f_time = (float)p_input->stream.p_selected_area->i_tell / 
326                  (float)p_input->stream.p_selected_area->i_size;
327     }    
328     else
329     {
330         f_time = 0.0;
331     }
332     return( f_time );
333 }
334
335 void VlcWrapper::SetTimeAsFloat( float f_position )
336 {
337     if( p_input != NULL )
338     {
339         input_Seek( p_input, 
340                    (long long)(p_input->stream.p_selected_area->i_size
341                        * f_position / SEEKSLIDER_RANGE ), 
342                    INPUT_SEEK_SET );
343     }
344 }
345
346 bool VlcWrapper::IsPlaying()
347 {
348
349         bool playing = false;
350         if ( p_input )
351         {
352                 switch ( p_input->stream.control.i_status )
353                 {
354                         case PLAYING_S:
355                         case FORWARD_S:
356                         case BACKWARD_S:
357                         case START_S:
358                                 playing = true;
359                     break;
360                         case PAUSE_S:
361                         case UNDEF_S:
362                         case NOT_STARTED_S:
363                         default:
364                                 break;
365                 }
366         }
367         return playing;
368
369 }
370
371 /************
372  * playlist *
373  ************/
374
375 void VlcWrapper::OpenFiles( BList* o_files, bool replace, int32 index )
376 {
377         if ( o_files && o_files->CountItems() > 0)
378         {
379             int size = PlaylistSize();
380                 bool wasEmpty = ( size < 1 );
381                 if ( index == -1 )
382                         index = PLAYLIST_END;
383                 int mode = index == PLAYLIST_END ? PLAYLIST_APPEND : PLAYLIST_INSERT;
384         
385             /* delete current playlist */
386             if( replace )
387             {
388                 for( int i = 0; i < size; i++ )
389                 {
390                     playlist_Delete( p_playlist, 0 );
391                 }
392             }
393         
394             /* insert files */
395             int32 count = o_files->CountItems();
396             for ( int32 i = count - 1; i >= 0; i-- )
397             {
398                 if ( BString* o_file = (BString *)o_files->RemoveItem( i ) )
399                 {
400                         playlist_Add( p_playlist, o_file->String(),
401                                       mode, index );
402                         if ( mode == PLAYLIST_INSERT )
403                                 index++;
404                         delete o_file;
405                 }
406             }
407             // TODO: implement a user setting
408             // if to start automatically
409             /* eventually restart playing */
410             if( replace || wasEmpty )
411             {
412                 playlist_Stop( p_playlist );
413                 playlist_Play( p_playlist );
414             }
415         }
416 }
417  
418 void VlcWrapper::OpenDisc(BString o_type, BString o_device, int i_title, int i_chapter)
419 {
420     if( config_GetInt( p_intf, "beos-dvdmenus" ) )
421         o_device.Prepend( "dvdplay:" );
422     else
423         o_device.Prepend( "dvdold:" );
424     playlist_Add( p_playlist, o_device.String(),
425                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
426 }
427
428 int VlcWrapper::PlaylistSize()
429 {
430     vlc_mutex_lock( &p_playlist->object_lock );
431     int i_size = p_playlist->i_size;
432     vlc_mutex_unlock( &p_playlist->object_lock );
433     return i_size;
434 }
435
436 char * VlcWrapper::PlaylistItemName( int i )
437 {
438    return p_playlist->pp_items[i]->psz_name;
439 }
440
441 int VlcWrapper::PlaylistCurrent()
442 {
443     return p_playlist->i_index;
444 }
445
446 bool VlcWrapper::PlaylistPlay()
447 {
448     if( PlaylistSize() )
449     {
450         playlist_Play( p_playlist );
451     }
452     return( true );
453 }
454
455 void VlcWrapper::PlaylistPause()
456 {
457     if( p_input )
458     {
459         input_SetStatus( p_input, INPUT_STATUS_PAUSE );
460     }
461 }
462
463 void VlcWrapper::PlaylistStop()
464 {
465     playlist_Stop( p_playlist );
466 }
467
468 void VlcWrapper::PlaylistNext()
469 {
470     playlist_Next( p_playlist );
471 }
472
473 void VlcWrapper::PlaylistPrev()
474 {
475     playlist_Prev( p_playlist );
476 }
477
478 void VlcWrapper::GetPlaylistInfo( int32& currentIndex, int32& maxIndex )
479 {
480         currentIndex = -1;
481         maxIndex = -1;
482         if ( p_playlist )
483         {
484             vlc_mutex_lock( &p_playlist->object_lock );
485
486                 maxIndex = p_playlist->i_size;
487                 if ( maxIndex > 0 )
488                         currentIndex = p_playlist->i_index/* + 1 -> why?!?*/;
489                 else
490                         maxIndex = -1;
491
492             vlc_mutex_unlock( &p_playlist->object_lock );
493         }
494 }
495
496 void VlcWrapper::PlaylistJumpTo( int pos )
497 {
498     playlist_Goto( p_playlist, pos );
499 }
500
501 void VlcWrapper::GetNavCapabilities( bool *canSkipPrev, bool *canSkipNext )
502 {
503         if ( canSkipPrev && canSkipNext )
504         {
505                 // init the parameters
506                 *canSkipPrev = false;
507                 *canSkipNext = false;
508                 // get playlist info
509                 int pos = PlaylistCurrent();
510                 int size = PlaylistSize();
511
512                 // see if we have got a stream going            
513                 if ( p_input )
514                 {
515                         vlc_mutex_lock( &p_input->stream.stream_lock );
516
517                         bool hasTitles = p_input->stream.i_area_nb > 1;
518                         int numChapters = p_input->stream.p_selected_area->i_part_nb;
519                         bool hasChapters = numChapters > 1;
520                         // first, look for chapters
521                         if ( hasChapters )
522                         {
523                                 *canSkipPrev = p_input->stream.p_selected_area->i_part > 0;
524                                 *canSkipNext = p_input->stream.p_selected_area->i_part <
525                                                                          p_input->stream.p_selected_area->i_part_nb - 1;
526                         }
527                         // if one of the skip capabilities is false,
528                         // make it depend on titles instead
529                         if ( !*canSkipPrev && hasTitles )
530                                 *canSkipPrev = p_input->stream.p_selected_area->i_id > 1;
531                         if ( !*canSkipNext && hasTitles )
532                                 *canSkipNext = p_input->stream.p_selected_area->i_id <
533                                                    p_input->stream.i_area_nb - 1;
534
535                         vlc_mutex_unlock( &p_input->stream.stream_lock );
536                 }
537                 // last but not least, make capabilities depend on playlist
538                 if ( !*canSkipPrev )
539                         *canSkipPrev = pos > 0;
540                 if ( !*canSkipNext )
541                         *canSkipNext = pos < size - 1;
542         }
543 }
544
545 void VlcWrapper::NavigatePrev()
546 {
547         bool hasSkiped = false;
548
549         // see if we have got a stream going            
550         if ( p_input )
551         {
552                 // get information from stream (lock it while looking at it)
553                 vlc_mutex_lock( &p_input->stream.stream_lock );
554
555                 int currentTitle = p_input->stream.p_selected_area->i_id;
556                 int currentChapter = p_input->stream.p_selected_area->i_part;
557                 int numTitles = p_input->stream.i_area_nb;
558                 bool hasTitles = numTitles > 1;
559                 int numChapters = p_input->stream.p_selected_area->i_part_nb;
560                 bool hasChapters = numChapters > 1;
561
562                 vlc_mutex_unlock( &p_input->stream.stream_lock );
563
564                 // first, look for chapters
565                 if ( hasChapters )
566                 {
567                         // skip to the previous chapter
568                         currentChapter--;
569
570                         if ( currentChapter >= 0 )
571                         {
572                                 ToggleChapter( currentChapter );
573                                 hasSkiped = true;
574                         }
575                 }
576                 // if we couldn't skip chapters, try titles instead
577                 if ( !hasSkiped && hasTitles )
578                 {
579                         // skip to the previous title
580                         currentTitle--;
581                         // disallow area 0 since it is used for video_ts.vob
582                         if( currentTitle > 0 )
583                         {
584                                 ToggleTitle(currentTitle);
585                                 hasSkiped = true;
586                         }
587                 }
588
589         }
590         // last but not least, skip to previous file
591         if ( !hasSkiped )
592                 PlaylistPrev();
593 }
594
595 void VlcWrapper::NavigateNext()
596 {
597         bool hasSkiped = false;
598
599         // see if we have got a stream going            
600         if ( p_input )
601         {
602                 // get information from stream (lock it while looking at it)
603                 vlc_mutex_lock( &p_input->stream.stream_lock );
604
605                 int currentTitle = p_input->stream.p_selected_area->i_id;
606                 int currentChapter = p_input->stream.p_selected_area->i_part;
607                 int numTitles = p_input->stream.i_area_nb;
608                 bool hasTitles = numTitles > 1;
609                 int numChapters = p_input->stream.p_selected_area->i_part_nb;
610                 bool hasChapters = numChapters > 1;
611
612                 vlc_mutex_unlock( &p_input->stream.stream_lock );
613
614                 // first, look for chapters
615                 if ( hasChapters )
616                 {
617                         // skip to the next chapter
618                         currentChapter++;
619                         if ( currentChapter < numChapters )
620                         {
621                                 ToggleChapter( currentChapter );
622                                 hasSkiped = true;
623                         }
624                 }
625                 // if we couldn't skip chapters, try titles instead
626                 if ( !hasSkiped && hasTitles )
627                 {
628                         // skip to the next title
629                         currentTitle++;
630                         // disallow area 0 since it is used for video_ts.vob
631                         if ( currentTitle < numTitles - 1 )
632                         {
633                                 ToggleTitle(currentTitle);
634                                 hasSkiped = true;
635                         }
636                 }
637
638         }
639         // last but not least, skip to next file
640         if ( !hasSkiped )
641                 PlaylistNext();
642 }
643
644 /*************************
645  * Playlist manipulation *
646  *************************/
647
648 // PlaylistLock
649 bool
650 VlcWrapper::PlaylistLock() const
651 {
652 // TODO: search and destroy -> deadlock!
653 return true;
654         if ( p_playlist )
655         {
656                 vlc_mutex_lock( &p_playlist->object_lock );
657                 return true;
658         }
659         return false;
660 }
661
662 // PlaylistUnlock
663 void
664 VlcWrapper::PlaylistUnlock() const
665 {
666 // TODO: search and destroy -> deadlock!
667 return;
668         vlc_mutex_unlock( &p_playlist->object_lock );
669 }
670
671 // PlaylistItemAt
672 void*
673 VlcWrapper::PlaylistItemAt( int index ) const
674 {
675         playlist_item_t* item = NULL;
676         if ( index >= 0 && index < p_playlist->i_size )
677                 item = p_playlist->pp_items[index];
678         return (void*)item;
679 }
680
681 // PlaylistRemoveItem
682 void*
683 VlcWrapper::PlaylistRemoveItem( int index ) const
684 {
685         playlist_item_t* copy = NULL;
686         // check if item exists at the provided index
687         if ( index >= 0 && index < p_playlist->i_size )
688         {
689                 playlist_item_t* item = p_playlist->pp_items[index];
690                 if ( item )
691                 {
692                         // make a copy of the removed item
693                         copy = (playlist_item_t*)PlaylistCloneItem( (void*)item );
694                         // remove item from playlist (unfortunately, this frees it)
695                         playlist_Delete( p_playlist, index );
696                 }
697         }
698         return (void*)copy;
699 }
700
701 // PlaylistRemoveItem
702 void*
703 VlcWrapper::PlaylistRemoveItem( void* item ) const
704 {
705         playlist_item_t* copy = NULL;
706         for ( int32 i = 0; i < p_playlist->i_size; i++ )
707         {
708                 if ( p_playlist->pp_items[i] == item )
709                 {
710                         copy = (playlist_item_t*)PlaylistRemoveItem( i );
711                         break;
712                 }
713         }
714         return (void*)copy;
715 }
716
717 // PlaylistAddItem
718 bool
719 VlcWrapper::PlaylistAddItem( void* item, int index ) const
720 {
721         if ( item )
722         {
723                 playlist_AddItem( p_playlist, (playlist_item_t*)item,
724                                                   PLAYLIST_INSERT, index );
725         }
726         // TODO: once playlist is returning useful info, return that instead
727         return true;
728 }
729
730 // PlaylistCloneItem
731 void*
732 VlcWrapper::PlaylistCloneItem( void* castToItem ) const
733 {
734         playlist_item_t* copy = NULL;
735         playlist_item_t* item = (playlist_item_t*)castToItem;
736         if ( item )
737         {
738                 copy = (playlist_item_t*)malloc( sizeof( playlist_item_t ) );
739                 if ( copy )
740                 {
741                         // make a copy of the item at index
742                         copy->psz_name = strdup( item->psz_name );
743                         copy->psz_uri  = strdup( item->psz_uri );
744                         copy->i_type = item->i_type;
745                         copy->i_status = item->i_status;
746                         copy->b_autodeletion = item->b_autodeletion;
747                 }
748         }
749         return (void*)copy;
750 }
751
752 // Careful! You need to know what you're doing here!
753 // The reason for having it, is to be able to deal with
754 // the rather lame list implementation of the playlist.
755 // It is meant to help manipulate the playlist with the above
756 // methods while keeping it valid.
757 //
758 // PlaylistSetPlaying
759 void
760 VlcWrapper::PlaylistSetPlaying( int index ) const
761 {
762         if ( index < 0 )
763                 index = 0;
764         if ( index >= p_playlist->i_size )
765                 index = p_playlist->i_size - 1;
766         p_playlist->i_index = index;
767 }
768
769
770 /*********
771  * audio *
772  *********/
773
774 unsigned short VlcWrapper::GetVolume()
775 {
776     unsigned short i_volume;
777     aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
778     return i_volume;
779 }
780
781 void VlcWrapper::SetVolume( int value )
782 {
783     if ( p_intf->p_sys->b_mute )
784     {
785         p_intf->p_sys->b_mute = 0;
786     }
787     aout_VolumeSet( p_intf, value );
788 }
789
790 void VlcWrapper::VolumeMute()
791 {
792         aout_VolumeGet( p_intf, &p_intf->p_sys->i_saved_volume );
793     aout_VolumeMute( p_intf, NULL );
794     p_intf->p_sys->b_mute = 1;
795 }
796
797 void VlcWrapper::VolumeRestore()
798 {
799     aout_VolumeSet( p_intf, p_intf->p_sys->i_saved_volume );
800     p_intf->p_sys->b_mute = 0;
801 }
802
803 bool VlcWrapper::IsMuted()
804 {
805     return p_intf->p_sys->b_mute;
806 }
807
808 /*******
809  * DVD *
810  *******/
811
812 bool VlcWrapper::HasTitles()
813 {
814     if( !p_input )
815     {
816         return false;
817     }
818     return ( p_input->stream.i_area_nb > 1 );
819 }
820
821 BList * VlcWrapper::GetTitles()
822 {
823     if( p_input )
824     {
825         vlc_mutex_lock( &p_input->stream.stream_lock );
826       
827         BList *list = new BList( p_input->stream.i_area_nb );
828         BMenuItem *menuItem;
829         BMessage *message;
830         
831         for( unsigned int i = 1; i < p_input->stream.i_area_nb; i++ )
832         {
833             message = new BMessage( TOGGLE_TITLE );
834             message->AddInt32( "index", i );
835             BString helper( "" );
836             helper << i;
837             menuItem = new BMenuItem( helper.String(), message );
838             menuItem->SetMarked( p_input->stream.p_selected_area->i_id == i );
839             list->AddItem( menuItem );
840         }
841         
842         vlc_mutex_unlock( &p_input->stream.stream_lock );
843
844         return list;
845     }
846     return NULL;
847 }
848
849 void VlcWrapper::PrevTitle()
850 {
851     int i_id;
852     i_id = p_input->stream.p_selected_area->i_id - 1;
853     if( i_id > 0 )
854     {
855         ToggleTitle(i_id);
856     }
857 }
858
859 void VlcWrapper::NextTitle()
860 {
861     unsigned int i_id;
862     i_id = p_input->stream.p_selected_area->i_id + 1;
863     if( i_id < p_input->stream.i_area_nb )
864     {
865         ToggleTitle(i_id);
866     }
867 }
868
869 void VlcWrapper::ToggleTitle(int i_title)
870 {
871     if( p_input != NULL )
872     {
873         input_ChangeArea( p_input,
874                           p_input->stream.pp_areas[i_title] );
875
876         vlc_mutex_lock( &p_input->stream.stream_lock );
877
878         vlc_mutex_unlock( &p_input->stream.stream_lock );
879     }
880 }
881
882 void VlcWrapper::TitleInfo( int32 &currentIndex, int32 &maxIndex )
883 {
884         currentIndex = -1;
885         maxIndex = -1;
886         if ( p_input )
887         {
888                 vlc_mutex_lock( &p_input->stream.stream_lock );
889
890                 maxIndex = p_input->stream.i_area_nb - 1;
891                 if ( maxIndex > 0)
892                         currentIndex = p_input->stream.p_selected_area->i_id;
893                 else
894                         maxIndex = -1;
895
896                 vlc_mutex_unlock( &p_input->stream.stream_lock );
897         }
898 }
899
900 bool VlcWrapper::HasChapters()
901 {
902     if( !p_input )
903     {
904         return false;
905     }
906     return ( p_input->stream.p_selected_area->i_part_nb > 1 );
907 }
908
909 BList * VlcWrapper::GetChapters()
910 {
911     if( p_input )
912     {
913         vlc_mutex_lock( &p_input->stream.stream_lock );
914       
915         BList *list = new BList( p_input->stream.p_selected_area->i_part_nb );
916         BMenuItem *menuItem;
917         BMessage *message;
918         
919         for( unsigned int i = 1;
920              i < p_input->stream.p_selected_area->i_part_nb + 1; i++ )
921         {
922             message = new BMessage( TOGGLE_CHAPTER );
923             message->AddInt32( "index", i );
924             BString helper( "" );
925             helper << i;
926             menuItem = new BMenuItem( helper.String(), message );
927             menuItem->SetMarked( p_input->stream.p_selected_area->i_part == i );
928             list->AddItem( menuItem );
929         }
930         
931         vlc_mutex_unlock( &p_input->stream.stream_lock );
932
933         return list;
934     }
935     return NULL;
936 }
937
938 void VlcWrapper::PrevChapter()
939 {
940     int i_id;
941     i_id = p_input->stream.p_selected_area->i_part - 1;
942     if( i_id >= 0 )
943     {
944         ToggleChapter(i_id);
945     }
946 }
947
948 void VlcWrapper::NextChapter()
949 {
950     int i_id;
951     i_id = p_input->stream.p_selected_area->i_part + 1;
952     if( i_id >= 0 )
953     {
954         ToggleChapter(i_id);
955     }
956 }
957
958 void VlcWrapper::ToggleChapter(int i_chapter)
959 {
960     if( p_input != NULL )
961     {
962         p_input->stream.p_selected_area->i_part = i_chapter;
963         input_ChangeArea( p_input,
964                           p_input->stream.p_selected_area );
965
966         vlc_mutex_lock( &p_input->stream.stream_lock );
967         vlc_mutex_unlock( &p_input->stream.stream_lock );
968     }
969 }
970
971 void VlcWrapper::ChapterInfo( int32 &currentIndex, int32 &maxIndex )
972 {
973         currentIndex = -1;
974         maxIndex = -1;
975         if ( p_input )
976         {
977                 vlc_mutex_lock( &p_input->stream.stream_lock );
978
979                 maxIndex = p_input->stream.p_selected_area->i_part_nb - 1;
980                 if ( maxIndex > 0)
981                         currentIndex = p_input->stream.p_selected_area->i_part;
982                 else
983                         maxIndex = -1;
984
985                 vlc_mutex_unlock( &p_input->stream.stream_lock );
986         }
987 }
988
989 /****************
990  * Miscellanous *
991  ****************/
992  
993 void VlcWrapper::LoadSubFile( const char * psz_file )
994 {
995     config_PutPsz( p_intf, "sub-file", strdup( psz_file ) );
996 }
997
998 void VlcWrapper::FilterChange()
999 {
1000     if( !p_input )
1001         return;
1002     
1003     vout_thread_t * p_vout;
1004     vlc_mutex_lock( &p_input->stream.stream_lock );
1005
1006     // Warn the vout we are about to change the filter chain
1007     p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
1008                                               FIND_ANYWHERE );
1009     if( p_vout )
1010     {
1011         p_vout->b_filter_change = VLC_TRUE;
1012         vlc_object_release( p_vout );
1013     }
1014
1015     // restart all video stream
1016     for( unsigned int i = 0; i < p_input->stream.i_es_number; i++ )
1017     {
1018         if( ( p_input->stream.pp_es[i]->i_cat == VIDEO_ES ) &&
1019             ( p_input->stream.pp_es[i]->p_decoder_fifo != NULL ) )
1020         {
1021             input_UnselectES( p_input, p_input->stream.pp_es[i] );
1022             input_SelectES( p_input, p_input->stream.pp_es[i] );
1023         }
1024     }
1025     vlc_mutex_unlock( &p_input->stream.stream_lock );
1026 }