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.40 2003/12/04 10:25:47 gbazin Exp $
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>
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.
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.
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 *****************************************************************************/
28 #include <InterfaceKit.h>
29 #include <SupportKit.h>
36 #include <input_ext-plugins.h> // needed here when compiling without plugins
37 #include <audio_output.h>
38 #include <aout_internal.h>
41 #include "VlcWrapper.h"
44 const char * _AddEllipsis( char * string )
47 temp = (char*) calloc( strlen( string ) + 4, 1 );
48 sprintf( temp, "%s%s", string, B_UTF8_ELLIPSIS );
53 VlcWrapper::VlcWrapper( intf_thread_t *p_interface )
57 p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
62 VlcWrapper::~VlcWrapper()
65 vlc_object_release( p_input );
68 vlc_object_release( p_playlist );
71 /* UpdateInput: updates p_input */
72 void VlcWrapper::UpdateInput()
75 p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
81 vlc_object_release( p_input );
87 /***************************
88 * input infos and control *
89 ***************************/
91 bool VlcWrapper::HasInput()
93 return ( p_input != NULL );
96 int VlcWrapper::InputStatus()
104 var_Get( p_input, "state", &state );
108 int VlcWrapper::InputRate()
115 return p_input->stream.control.i_rate;
118 void VlcWrapper::InputSetRate( int rate )
125 input_SetRate( p_input, rate );
128 BList * VlcWrapper::GetChannels( int i_cat )
134 const char* fieldName;
140 what = SELECT_CHANNEL;
141 fieldName = "channel";
146 what = SELECT_SUBTITLE;
147 fieldName = "subtitle";
154 vlc_mutex_lock( &p_input->stream.stream_lock );
156 /* find which track is currently playing */
157 es_descriptor_t *p_es = NULL;
158 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
160 if( p_input->stream.pp_selected_es[i]->i_cat == i_cat )
161 p_es = p_input->stream.pp_selected_es[i];
164 /* build a list of all tracks */
165 BList *list = new BList( p_input->stream.i_es_number );
171 message = new BMessage( what );
172 message->AddInt32( fieldName, -1 );
173 menuItem = new BMenuItem( _("None"), message );
175 menuItem->SetMarked( true );
176 list->AddItem( menuItem );
178 for( i = 0; i < p_input->stream.i_es_number; i++ )
180 if( p_input->stream.pp_es[i]->i_cat == i_cat )
182 message = new BMessage( what );
183 message->AddInt32( fieldName, i );
184 if( !p_input->stream.pp_es[i]->psz_desc ||
185 !*p_input->stream.pp_es[i]->psz_desc )
186 trackName = _("<unknown>");
188 trackName = strdup( p_input->stream.pp_es[i]->psz_desc );
189 menuItem = new BMenuItem( trackName, message );
190 if( p_input->stream.pp_es[i] == p_es )
191 menuItem->SetMarked( true );
192 list->AddItem( menuItem );
196 vlc_mutex_unlock( &p_input->stream.stream_lock );
203 void VlcWrapper::ToggleLanguage( int i_language )
205 es_descriptor_t * p_es = NULL;
206 es_descriptor_t * p_es_old = NULL;
208 vlc_mutex_lock( &p_input->stream.stream_lock );
209 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
211 if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
213 p_es_old = p_input->stream.pp_selected_es[i];
217 vlc_mutex_unlock( &p_input->stream.stream_lock );
219 if( i_language != -1 )
221 p_es = p_input->stream.pp_es[i_language];
223 if( p_es == p_es_old )
229 input_ToggleES( p_input, p_es_old, VLC_FALSE );
233 input_ToggleES( p_input, p_es, VLC_TRUE );
237 void VlcWrapper::ToggleSubtitle( int i_subtitle )
239 es_descriptor_t * p_es = NULL;
240 es_descriptor_t * p_es_old = NULL;
242 vlc_mutex_lock( &p_input->stream.stream_lock );
243 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
245 if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
247 p_es_old = p_input->stream.pp_selected_es[i];
251 vlc_mutex_unlock( &p_input->stream.stream_lock );
253 if( i_subtitle != -1 )
255 p_es = p_input->stream.pp_es[i_subtitle];
257 if( p_es == p_es_old )
263 input_ToggleES( p_input, p_es_old, VLC_FALSE );
267 input_ToggleES( p_input, p_es, VLC_TRUE );
271 const char * VlcWrapper::GetTimeAsString()
273 static char psz_time[ MSTRTIME_MAX_SIZE ];
281 var_Get( p_input, "time", &time );
283 mtime_t seconds = time.i_time / 1000000;
284 sprintf( psz_time, "%d:%02d:%02d",
285 (int) ( seconds / (60 * 60 ) ),
286 (int) ( ( seconds / 60 ) % 60 ),
287 (int) ( seconds % 60 ) );
292 float VlcWrapper::GetTimeAsFloat()
300 var_Get( p_input, "position", &pos );
304 void VlcWrapper::SetTimeAsFloat( float f_position )
312 pos.f_float = f_position / SEEKSLIDER_RANGE;
313 var_Set( p_input, "position", pos );
316 bool VlcWrapper::IsPlaying()
318 bool playing = false;
321 switch( p_input->stream.control.i_status )
342 void VlcWrapper::OpenFiles( BList* o_files, bool replace, int32 index )
344 if ( o_files && o_files->CountItems() > 0)
346 int size = PlaylistSize();
347 bool wasEmpty = ( size < 1 );
349 index = PLAYLIST_END;
350 int mode = index == PLAYLIST_END ? PLAYLIST_APPEND : PLAYLIST_INSERT;
352 /* delete current playlist */
355 for( int i = 0; i < size; i++ )
357 playlist_Delete( p_playlist, 0 );
362 int32 count = o_files->CountItems();
363 for ( int32 i = count - 1; i >= 0; i-- )
365 if ( BString* o_file = (BString *)o_files->RemoveItem( i ) )
367 playlist_Add( p_playlist, o_file->String(),
369 if ( mode == PLAYLIST_INSERT )
374 // TODO: implement a user setting
375 // if to start automatically
376 /* eventually restart playing */
377 if( replace || wasEmpty )
379 playlist_Stop( p_playlist );
380 playlist_Play( p_playlist );
385 void VlcWrapper::OpenDisc(BString o_type, BString o_device, int i_title, int i_chapter)
387 if( config_GetInt( p_intf, "beos-dvdmenus" ) )
388 o_device.Prepend( "dvdplay:" );
390 o_device.Prepend( "dvdold:" );
391 playlist_Add( p_playlist, o_device.String(), 0, 0,
392 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
395 int VlcWrapper::PlaylistSize()
397 vlc_mutex_lock( &p_playlist->object_lock );
398 int i_size = p_playlist->i_size;
399 vlc_mutex_unlock( &p_playlist->object_lock );
403 char * VlcWrapper::PlaylistItemName( int i )
405 return p_playlist->pp_items[i]->psz_name;
408 int VlcWrapper::PlaylistCurrent()
410 return p_playlist->i_index;
413 bool VlcWrapper::PlaylistPlay()
417 playlist_Play( p_playlist );
422 void VlcWrapper::PlaylistPause()
426 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
430 void VlcWrapper::PlaylistStop()
432 playlist_Stop( p_playlist );
435 void VlcWrapper::PlaylistNext()
437 playlist_Next( p_playlist );
440 void VlcWrapper::PlaylistPrev()
442 playlist_Prev( p_playlist );
445 void VlcWrapper::GetPlaylistInfo( int32& currentIndex, int32& maxIndex )
451 vlc_mutex_lock( &p_playlist->object_lock );
453 maxIndex = p_playlist->i_size;
455 currentIndex = p_playlist->i_index/* + 1 -> why?!?*/;
459 vlc_mutex_unlock( &p_playlist->object_lock );
463 void VlcWrapper::PlaylistJumpTo( int pos )
465 playlist_Goto( p_playlist, pos );
468 void VlcWrapper::GetNavCapabilities( bool *canSkipPrev, bool *canSkipNext )
470 if ( canSkipPrev && canSkipNext )
472 // init the parameters
473 *canSkipPrev = false;
474 *canSkipNext = false;
476 int pos = PlaylistCurrent();
477 int size = PlaylistSize();
479 // see if we have got a stream going
482 vlc_mutex_lock( &p_input->stream.stream_lock );
484 bool hasTitles = p_input->stream.i_area_nb > 1;
485 int numChapters = p_input->stream.p_selected_area->i_part_nb;
486 bool hasChapters = numChapters > 1;
487 // first, look for chapters
490 *canSkipPrev = p_input->stream.p_selected_area->i_part > 0;
491 *canSkipNext = p_input->stream.p_selected_area->i_part <
492 p_input->stream.p_selected_area->i_part_nb - 1;
494 // if one of the skip capabilities is false,
495 // make it depend on titles instead
496 if ( !*canSkipPrev && hasTitles )
497 *canSkipPrev = p_input->stream.p_selected_area->i_id > 1;
498 if ( !*canSkipNext && hasTitles )
499 *canSkipNext = p_input->stream.p_selected_area->i_id <
500 p_input->stream.i_area_nb - 1;
502 vlc_mutex_unlock( &p_input->stream.stream_lock );
504 // last but not least, make capabilities depend on playlist
506 *canSkipPrev = pos > 0;
508 *canSkipNext = pos < size - 1;
512 void VlcWrapper::NavigatePrev()
514 bool hasSkiped = false;
516 // see if we have got a stream going
519 // get information from stream (lock it while looking at it)
520 vlc_mutex_lock( &p_input->stream.stream_lock );
522 int currentTitle = p_input->stream.p_selected_area->i_id;
523 int currentChapter = p_input->stream.p_selected_area->i_part;
524 int numTitles = p_input->stream.i_area_nb;
525 bool hasTitles = numTitles > 1;
526 int numChapters = p_input->stream.p_selected_area->i_part_nb;
527 bool hasChapters = numChapters > 1;
529 vlc_mutex_unlock( &p_input->stream.stream_lock );
531 // first, look for chapters
534 // skip to the previous chapter
537 if ( currentChapter >= 0 )
539 ToggleChapter( currentChapter );
543 // if we couldn't skip chapters, try titles instead
544 if ( !hasSkiped && hasTitles )
546 // skip to the previous title
548 // disallow area 0 since it is used for video_ts.vob
549 if( currentTitle > 0 )
551 ToggleTitle(currentTitle);
557 // last but not least, skip to previous file
562 void VlcWrapper::NavigateNext()
564 bool hasSkiped = false;
566 // see if we have got a stream going
569 // get information from stream (lock it while looking at it)
570 vlc_mutex_lock( &p_input->stream.stream_lock );
572 int currentTitle = p_input->stream.p_selected_area->i_id;
573 int currentChapter = p_input->stream.p_selected_area->i_part;
574 int numTitles = p_input->stream.i_area_nb;
575 bool hasTitles = numTitles > 1;
576 int numChapters = p_input->stream.p_selected_area->i_part_nb;
577 bool hasChapters = numChapters > 1;
579 vlc_mutex_unlock( &p_input->stream.stream_lock );
581 // first, look for chapters
584 // skip to the next chapter
586 if ( currentChapter < numChapters )
588 ToggleChapter( currentChapter );
592 // if we couldn't skip chapters, try titles instead
593 if ( !hasSkiped && hasTitles )
595 // skip to the next title
597 // disallow area 0 since it is used for video_ts.vob
598 if ( currentTitle < numTitles - 1 )
600 ToggleTitle(currentTitle);
606 // last but not least, skip to next file
611 /*************************
612 * Playlist manipulation *
613 *************************/
617 VlcWrapper::PlaylistLock() const
619 // TODO: search and destroy -> deadlock!
623 vlc_mutex_lock( &p_playlist->object_lock );
631 VlcWrapper::PlaylistUnlock() const
633 // TODO: search and destroy -> deadlock!
635 vlc_mutex_unlock( &p_playlist->object_lock );
640 VlcWrapper::PlaylistItemAt( int index ) const
642 playlist_item_t* item = NULL;
643 if ( index >= 0 && index < p_playlist->i_size )
644 item = p_playlist->pp_items[index];
648 // PlaylistRemoveItem
650 VlcWrapper::PlaylistRemoveItem( int index ) const
652 playlist_item_t* copy = NULL;
653 // check if item exists at the provided index
654 if ( index >= 0 && index < p_playlist->i_size )
656 playlist_item_t* item = p_playlist->pp_items[index];
659 // make a copy of the removed item
660 copy = (playlist_item_t*)PlaylistCloneItem( (void*)item );
661 // remove item from playlist (unfortunately, this frees it)
662 playlist_Delete( p_playlist, index );
668 // PlaylistRemoveItem
670 VlcWrapper::PlaylistRemoveItem( void* item ) const
672 playlist_item_t* copy = NULL;
673 for ( int32 i = 0; i < p_playlist->i_size; i++ )
675 if ( p_playlist->pp_items[i] == item )
677 copy = (playlist_item_t*)PlaylistRemoveItem( i );
686 VlcWrapper::PlaylistAddItem( void* item, int index ) const
690 playlist_AddItem( p_playlist, (playlist_item_t*)item,
691 PLAYLIST_INSERT, index );
693 // TODO: once playlist is returning useful info, return that instead
699 VlcWrapper::PlaylistCloneItem( void* castToItem ) const
701 playlist_item_t* copy = NULL;
702 playlist_item_t* item = (playlist_item_t*)castToItem;
705 copy = (playlist_item_t*)malloc( sizeof( playlist_item_t ) );
708 // make a copy of the item at index
709 copy->psz_name = strdup( item->psz_name );
710 copy->psz_uri = strdup( item->psz_uri );
711 copy->i_type = item->i_type;
712 copy->i_status = item->i_status;
713 copy->b_autodeletion = item->b_autodeletion;
719 // Careful! You need to know what you're doing here!
720 // The reason for having it, is to be able to deal with
721 // the rather lame list implementation of the playlist.
722 // It is meant to help manipulate the playlist with the above
723 // methods while keeping it valid.
725 // PlaylistSetPlaying
727 VlcWrapper::PlaylistSetPlaying( int index ) const
731 if ( index >= p_playlist->i_size )
732 index = p_playlist->i_size - 1;
733 p_playlist->i_index = index;
741 unsigned short VlcWrapper::GetVolume()
743 unsigned short i_volume;
744 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
748 void VlcWrapper::SetVolume( int value )
750 if ( p_intf->p_sys->b_mute )
752 p_intf->p_sys->b_mute = 0;
754 aout_VolumeSet( p_intf, value );
757 void VlcWrapper::VolumeMute()
759 aout_VolumeMute( p_intf, NULL );
760 p_intf->p_sys->b_mute = 1;
763 void VlcWrapper::VolumeRestore()
765 audio_volume_t dummy;
766 aout_VolumeMute( p_intf, &dummy );
767 p_intf->p_sys->b_mute = 0;
770 bool VlcWrapper::IsMuted()
772 return p_intf->p_sys->b_mute;
779 bool VlcWrapper::IsUsingMenus()
784 vlc_mutex_lock( &p_playlist->object_lock );
785 if( p_playlist->i_index < 0 )
787 vlc_mutex_unlock( &p_playlist->object_lock );
791 char * psz_name = p_playlist->pp_items[p_playlist->i_index]->psz_name;
792 if( !strncmp( psz_name, "dvdplay:", 8 ) )
794 vlc_mutex_unlock( &p_playlist->object_lock );
797 vlc_mutex_unlock( &p_playlist->object_lock );
802 bool VlcWrapper::HasTitles()
807 return ( p_input->stream.i_area_nb > 1 );
810 BList * VlcWrapper::GetTitles()
814 vlc_mutex_lock( &p_input->stream.stream_lock );
816 BList *list = new BList( p_input->stream.i_area_nb );
820 for( unsigned int i = 1; i < p_input->stream.i_area_nb; i++ )
822 message = new BMessage( TOGGLE_TITLE );
823 message->AddInt32( "index", i );
824 BString helper( "" );
826 menuItem = new BMenuItem( helper.String(), message );
827 menuItem->SetMarked( p_input->stream.p_selected_area->i_id == i );
828 list->AddItem( menuItem );
831 vlc_mutex_unlock( &p_input->stream.stream_lock );
838 void VlcWrapper::PrevTitle()
841 i_id = p_input->stream.p_selected_area->i_id - 1;
848 void VlcWrapper::NextTitle()
851 i_id = p_input->stream.p_selected_area->i_id + 1;
852 if( i_id < p_input->stream.i_area_nb )
858 void VlcWrapper::ToggleTitle(int i_title)
860 if( p_input != NULL )
862 input_ChangeArea( p_input,
863 p_input->stream.pp_areas[i_title] );
865 vlc_mutex_lock( &p_input->stream.stream_lock );
867 vlc_mutex_unlock( &p_input->stream.stream_lock );
871 void VlcWrapper::TitleInfo( int32 ¤tIndex, int32 &maxIndex )
877 vlc_mutex_lock( &p_input->stream.stream_lock );
879 maxIndex = p_input->stream.i_area_nb - 1;
881 currentIndex = p_input->stream.p_selected_area->i_id;
885 vlc_mutex_unlock( &p_input->stream.stream_lock );
889 bool VlcWrapper::HasChapters()
895 return ( p_input->stream.p_selected_area->i_part_nb > 1 );
898 BList * VlcWrapper::GetChapters()
902 vlc_mutex_lock( &p_input->stream.stream_lock );
904 BList *list = new BList( p_input->stream.p_selected_area->i_part_nb );
908 for( unsigned int i = 1;
909 i < p_input->stream.p_selected_area->i_part_nb + 1; i++ )
911 message = new BMessage( TOGGLE_CHAPTER );
912 message->AddInt32( "index", i );
913 BString helper( "" );
915 menuItem = new BMenuItem( helper.String(), message );
916 menuItem->SetMarked( p_input->stream.p_selected_area->i_part == i );
917 list->AddItem( menuItem );
920 vlc_mutex_unlock( &p_input->stream.stream_lock );
927 void VlcWrapper::PrevChapter()
930 i_id = p_input->stream.p_selected_area->i_part - 1;
937 void VlcWrapper::NextChapter()
940 i_id = p_input->stream.p_selected_area->i_part + 1;
947 void VlcWrapper::ToggleChapter(int i_chapter)
949 if( p_input != NULL )
951 p_input->stream.p_selected_area->i_part = i_chapter;
952 input_ChangeArea( p_input,
953 p_input->stream.p_selected_area );
955 vlc_mutex_lock( &p_input->stream.stream_lock );
956 vlc_mutex_unlock( &p_input->stream.stream_lock );
960 void VlcWrapper::ChapterInfo( int32 ¤tIndex, int32 &maxIndex )
966 vlc_mutex_lock( &p_input->stream.stream_lock );
968 maxIndex = p_input->stream.p_selected_area->i_part_nb - 1;
970 currentIndex = p_input->stream.p_selected_area->i_part;
974 vlc_mutex_unlock( &p_input->stream.stream_lock );
982 void VlcWrapper::LoadSubFile( const char * psz_file )
984 config_PutPsz( p_intf, "sub-file", strdup( psz_file ) );
987 void VlcWrapper::FilterChange()
992 vout_thread_t * p_vout;
993 vlc_mutex_lock( &p_input->stream.stream_lock );
995 // Warn the vout we are about to change the filter chain
996 p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
1000 p_vout->b_filter_change = VLC_TRUE;
1001 vlc_object_release( p_vout );
1004 // restart all video stream
1005 for( unsigned int i = 0; i < p_input->stream.i_es_number; i++ )
1007 if( ( p_input->stream.pp_es[i]->i_cat == VIDEO_ES ) &&
1008 ( p_input->stream.pp_es[i]->p_dec != NULL ) )
1010 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1011 input_SelectES( p_input, p_input->stream.pp_es[i] );
1014 vlc_mutex_unlock( &p_input->stream.stream_lock );