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.27 2003/04/22 16:36:16 titer 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 )
46 BString newString( string );
47 newString << B_UTF8_ELLIPSIS;
48 return newString.String();
52 VlcWrapper::VlcWrapper( intf_thread_t *p_interface )
56 p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
61 VlcWrapper::~VlcWrapper()
65 vlc_object_release( p_input );
69 vlc_object_release( p_playlist );
73 /* UpdateInput: updates p_input, returns true if the interface needs to
75 bool VlcWrapper::UpdateInput()
79 p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
87 vlc_object_release( p_input );
96 /***************************
97 * input infos and control *
98 ***************************/
100 bool VlcWrapper::HasInput()
102 return ( p_input != NULL );
105 int VlcWrapper::InputStatus()
111 return p_input->stream.control.i_status;
114 int VlcWrapper::InputRate()
120 return p_input->stream.control.i_rate;
123 void VlcWrapper::InputSlower()
125 if( p_input != NULL )
127 input_SetStatus( p_input, INPUT_STATUS_SLOWER );
131 void VlcWrapper::InputFaster()
133 if( p_input != NULL )
135 input_SetStatus( p_input, INPUT_STATUS_FASTER );
139 BList * VlcWrapper::GetChannels( int i_cat )
145 const char* fieldName;
151 what = SELECT_CHANNEL;
152 fieldName = "channel";
157 what = SELECT_SUBTITLE;
158 fieldName = "subtitle";
165 vlc_mutex_lock( &p_input->stream.stream_lock );
167 /* find which track is currently playing */
168 es_descriptor_t *p_es = NULL;
169 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
171 if( p_input->stream.pp_selected_es[i]->i_cat == i_cat )
172 p_es = p_input->stream.pp_selected_es[i];
175 /* build a list of all tracks */
176 BList *list = new BList( p_input->stream.i_es_number );
182 message = new BMessage( what );
183 message->AddInt32( fieldName, -1 );
184 menuItem = new BMenuItem( _("None"), message );
186 menuItem->SetMarked( true );
187 list->AddItem( menuItem );
189 for( i = 0; i < p_input->stream.i_es_number; i++ )
191 if( p_input->stream.pp_es[i]->i_cat == i_cat )
193 message = new BMessage( what );
194 message->AddInt32( fieldName, i );
195 if( strlen( p_input->stream.pp_es[i]->psz_desc ) )
196 trackName = strdup( p_input->stream.pp_es[i]->psz_desc );
198 trackName = _("<unknown>");
199 menuItem = new BMenuItem( trackName, message );
200 if( p_input->stream.pp_es[i] == p_es )
201 menuItem->SetMarked( true );
202 list->AddItem( menuItem );
206 vlc_mutex_unlock( &p_input->stream.stream_lock );
213 void VlcWrapper::ToggleLanguage( int i_language )
215 es_descriptor_t * p_es = NULL;
216 es_descriptor_t * p_es_old = NULL;
218 vlc_mutex_lock( &p_input->stream.stream_lock );
219 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
221 if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
223 p_es_old = p_input->stream.pp_selected_es[i];
227 vlc_mutex_unlock( &p_input->stream.stream_lock );
229 if( i_language != -1 )
231 p_es = p_input->stream.pp_es[i_language];
233 if( p_es == p_es_old )
239 input_ToggleES( p_input, p_es_old, VLC_FALSE );
243 input_ToggleES( p_input, p_es, VLC_TRUE );
247 void VlcWrapper::ToggleSubtitle( int i_subtitle )
249 es_descriptor_t * p_es = NULL;
250 es_descriptor_t * p_es_old = NULL;
252 vlc_mutex_lock( &p_input->stream.stream_lock );
253 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
255 if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
257 p_es_old = p_input->stream.pp_selected_es[i];
261 vlc_mutex_unlock( &p_input->stream.stream_lock );
263 if( i_subtitle != -1 )
265 p_es = p_input->stream.pp_es[i_subtitle];
267 if( p_es == p_es_old )
273 input_ToggleES( p_input, p_es_old, VLC_FALSE );
277 input_ToggleES( p_input, p_es, VLC_TRUE );
281 const char * VlcWrapper::GetTimeAsString()
283 static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
285 if( p_input == NULL )
290 input_OffsetToTime( p_input,
292 p_input->stream.p_selected_area->i_tell );
294 return(psz_currenttime);
297 float VlcWrapper::GetTimeAsFloat()
301 if( p_input != NULL )
303 f_time = (float)p_input->stream.p_selected_area->i_tell /
304 (float)p_input->stream.p_selected_area->i_size;
313 void VlcWrapper::SetTimeAsFloat( float f_position )
315 if( p_input != NULL )
318 (long long int)(p_input->stream.p_selected_area->i_size
319 * f_position / SEEKSLIDER_RANGE ),
324 bool VlcWrapper::IsPlaying()
327 bool playing = false;
330 switch ( p_input->stream.control.i_status )
353 void VlcWrapper::OpenFiles( BList* o_files, bool replace, int32 index )
355 if ( o_files && o_files->CountItems() > 0)
357 int size = PlaylistSize();
358 bool wasEmpty = ( size < 1 );
360 index = PLAYLIST_END;
361 int mode = index == PLAYLIST_END ? PLAYLIST_APPEND : PLAYLIST_INSERT;
363 /* delete current playlist */
366 for( int i = 0; i < size; i++ )
368 playlist_Delete( p_playlist, 0 );
373 int32 count = o_files->CountItems();
374 for ( int32 i = count - 1; i >= 0; i-- )
376 if ( BString* o_file = (BString *)o_files->RemoveItem( i ) )
378 playlist_Add( p_playlist, o_file->String(),
380 if ( mode == PLAYLIST_INSERT )
385 // TODO: implement a user setting
386 // if to start automatically
387 /* eventually restart playing */
388 if( replace || wasEmpty )
390 playlist_Stop( p_playlist );
391 playlist_Play( p_playlist );
396 void VlcWrapper::OpenDisc(BString o_type, BString o_device, int i_title, int i_chapter)
398 if( p_intf->p_sys->b_dvdmenus )
399 o_device.Prepend( "dvd:" );
401 o_device.Prepend( "dvdold:" );
402 playlist_Add( p_playlist, o_device.String(),
403 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
406 int VlcWrapper::PlaylistSize()
408 vlc_mutex_lock( &p_playlist->object_lock );
409 int i_size = p_playlist->i_size;
410 vlc_mutex_unlock( &p_playlist->object_lock );
414 char * VlcWrapper::PlaylistItemName( int i )
416 return p_playlist->pp_items[i]->psz_name;
419 int VlcWrapper::PlaylistCurrent()
421 return p_playlist->i_index;
424 bool VlcWrapper::PlaylistPlay()
428 playlist_Play( p_playlist );
433 void VlcWrapper::PlaylistPause()
437 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
441 void VlcWrapper::PlaylistStop()
443 playlist_Stop( p_playlist );
446 void VlcWrapper::PlaylistNext()
448 playlist_Next( p_playlist );
451 void VlcWrapper::PlaylistPrev()
453 playlist_Prev( p_playlist );
456 void VlcWrapper::GetPlaylistInfo( int32& currentIndex, int32& maxIndex )
462 vlc_mutex_lock( &p_playlist->object_lock );
464 maxIndex = p_playlist->i_size;
466 currentIndex = p_playlist->i_index/* + 1 -> why?!?*/;
470 vlc_mutex_unlock( &p_playlist->object_lock );
474 void VlcWrapper::PlaylistJumpTo( int pos )
476 playlist_Goto( p_playlist, pos );
479 void VlcWrapper::GetNavCapabilities( bool *canSkipPrev, bool *canSkipNext )
481 if ( canSkipPrev && canSkipNext )
483 // init the parameters
484 *canSkipPrev = false;
485 *canSkipNext = false;
487 int pos = PlaylistCurrent();
488 int size = PlaylistSize();
490 // see if we have got a stream going
493 vlc_mutex_lock( &p_input->stream.stream_lock );
495 bool hasTitles = p_input->stream.i_area_nb > 1;
496 int numChapters = p_input->stream.p_selected_area->i_part_nb;
497 bool hasChapters = numChapters > 1;
498 // first, look for chapters
501 *canSkipPrev = p_input->stream.p_selected_area->i_part > 0;
502 *canSkipNext = p_input->stream.p_selected_area->i_part <
503 p_input->stream.p_selected_area->i_part_nb - 1;
505 // if one of the skip capabilities is false,
506 // make it depend on titles instead
507 if ( !*canSkipPrev && hasTitles )
508 *canSkipPrev = p_input->stream.p_selected_area->i_id > 1;
509 if ( !*canSkipNext && hasTitles )
510 *canSkipNext = p_input->stream.p_selected_area->i_id <
511 p_input->stream.i_area_nb - 1;
513 vlc_mutex_unlock( &p_input->stream.stream_lock );
515 // last but not least, make capabilities depend on playlist
517 *canSkipPrev = pos > 0;
519 *canSkipNext = pos < size - 1;
523 void VlcWrapper::NavigatePrev()
525 bool hasSkiped = false;
527 // see if we have got a stream going
530 // get information from stream (lock it while looking at it)
531 vlc_mutex_lock( &p_input->stream.stream_lock );
533 int currentTitle = p_input->stream.p_selected_area->i_id;
534 int currentChapter = p_input->stream.p_selected_area->i_part;
535 int numTitles = p_input->stream.i_area_nb;
536 bool hasTitles = numTitles > 1;
537 int numChapters = p_input->stream.p_selected_area->i_part_nb;
538 bool hasChapters = numChapters > 1;
540 vlc_mutex_unlock( &p_input->stream.stream_lock );
542 // first, look for chapters
545 // skip to the previous chapter
548 if ( currentChapter >= 0 )
550 ToggleChapter( currentChapter );
554 // if we couldn't skip chapters, try titles instead
555 if ( !hasSkiped && hasTitles )
557 // skip to the previous title
559 // disallow area 0 since it is used for video_ts.vob
560 if( currentTitle > 0 )
562 ToggleTitle(currentTitle);
568 // last but not least, skip to previous file
573 void VlcWrapper::NavigateNext()
575 bool hasSkiped = false;
577 // see if we have got a stream going
580 // get information from stream (lock it while looking at it)
581 vlc_mutex_lock( &p_input->stream.stream_lock );
583 int currentTitle = p_input->stream.p_selected_area->i_id;
584 int currentChapter = p_input->stream.p_selected_area->i_part;
585 int numTitles = p_input->stream.i_area_nb;
586 bool hasTitles = numTitles > 1;
587 int numChapters = p_input->stream.p_selected_area->i_part_nb;
588 bool hasChapters = numChapters > 1;
590 vlc_mutex_unlock( &p_input->stream.stream_lock );
592 // first, look for chapters
595 // skip to the next chapter
597 if ( currentChapter < numChapters )
599 ToggleChapter( currentChapter );
603 // if we couldn't skip chapters, try titles instead
604 if ( !hasSkiped && hasTitles )
606 // skip to the next title
608 // disallow area 0 since it is used for video_ts.vob
609 if ( currentTitle < numTitles - 1 )
611 ToggleTitle(currentTitle);
617 // last but not least, skip to next file
622 /*************************
623 * Playlist manipulation *
624 *************************/
628 VlcWrapper::PlaylistLock() const
630 // TODO: search and destroy -> deadlock!
634 vlc_mutex_lock( &p_playlist->object_lock );
642 VlcWrapper::PlaylistUnlock() const
644 // TODO: search and destroy -> deadlock!
646 vlc_mutex_unlock( &p_playlist->object_lock );
651 VlcWrapper::PlaylistItemAt( int index ) const
653 playlist_item_t* item = NULL;
654 if ( index >= 0 && index < p_playlist->i_size )
655 item = p_playlist->pp_items[index];
659 // PlaylistRemoveItem
661 VlcWrapper::PlaylistRemoveItem( int index ) const
663 playlist_item_t* copy = NULL;
664 // check if item exists at the provided index
665 if ( index >= 0 && index < p_playlist->i_size )
667 playlist_item_t* item = p_playlist->pp_items[index];
670 // make a copy of the removed item
671 copy = (playlist_item_t*)PlaylistCloneItem( (void*)item );
672 // remove item from playlist (unfortunately, this frees it)
673 playlist_Delete( p_playlist, index );
679 // PlaylistRemoveItem
681 VlcWrapper::PlaylistRemoveItem( void* item ) const
683 playlist_item_t* copy = NULL;
684 for ( int32 i = 0; i < p_playlist->i_size; i++ )
686 if ( p_playlist->pp_items[i] == item )
688 copy = (playlist_item_t*)PlaylistRemoveItem( i );
697 VlcWrapper::PlaylistAddItem( void* item, int index ) const
701 playlist_AddItem( p_playlist, (playlist_item_t*)item,
702 PLAYLIST_INSERT, index );
704 // TODO: once playlist is returning useful info, return that instead
710 VlcWrapper::PlaylistCloneItem( void* castToItem ) const
712 playlist_item_t* copy = NULL;
713 playlist_item_t* item = (playlist_item_t*)castToItem;
716 copy = (playlist_item_t*)malloc( sizeof( playlist_item_t ) );
719 // make a copy of the item at index
720 copy->psz_name = strdup( item->psz_name );
721 copy->psz_uri = strdup( item->psz_uri );
722 copy->i_type = item->i_type;
723 copy->i_status = item->i_status;
724 copy->b_autodeletion = item->b_autodeletion;
730 // Careful! You need to know what you're doing here!
731 // The reason for having it, is to be able to deal with
732 // the rather lame list implementation of the playlist.
733 // It is meant to help manipulate the playlist with the above
734 // methods while keeping it valid.
736 // PlaylistSetPlaying
738 VlcWrapper::PlaylistSetPlaying( int index ) const
742 if ( index >= p_playlist->i_size )
743 index = p_playlist->i_size - 1;
744 p_playlist->i_index = index;
752 unsigned short VlcWrapper::GetVolume()
754 unsigned short i_volume;
755 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
759 void VlcWrapper::SetVolume( int value )
761 if ( p_intf->p_sys->b_mute )
763 p_intf->p_sys->b_mute = 0;
765 aout_VolumeSet( p_intf, value );
768 void VlcWrapper::VolumeMute()
770 aout_VolumeGet( p_intf, &p_intf->p_sys->i_saved_volume );
771 aout_VolumeMute( p_intf, NULL );
772 p_intf->p_sys->b_mute = 1;
775 void VlcWrapper::VolumeRestore()
777 aout_VolumeSet( p_intf, p_intf->p_sys->i_saved_volume );
778 p_intf->p_sys->b_mute = 0;
781 bool VlcWrapper::IsMuted()
783 return p_intf->p_sys->b_mute;
790 bool VlcWrapper::HasTitles()
796 return ( p_input->stream.i_area_nb > 1 );
799 BList * VlcWrapper::GetTitles()
803 vlc_mutex_lock( &p_input->stream.stream_lock );
805 BList *list = new BList( p_input->stream.i_area_nb );
809 for( unsigned int i = 1; i < p_input->stream.i_area_nb; i++ )
811 message = new BMessage( TOGGLE_TITLE );
812 message->AddInt32( "index", i );
813 BString helper( "" );
815 menuItem = new BMenuItem( helper.String(), message );
816 menuItem->SetMarked( p_input->stream.p_selected_area->i_id == i );
817 list->AddItem( menuItem );
820 vlc_mutex_unlock( &p_input->stream.stream_lock );
827 void VlcWrapper::PrevTitle()
830 i_id = p_input->stream.p_selected_area->i_id - 1;
837 void VlcWrapper::NextTitle()
840 i_id = p_input->stream.p_selected_area->i_id + 1;
841 if( i_id < p_input->stream.i_area_nb )
847 void VlcWrapper::ToggleTitle(int i_title)
849 if( p_input != NULL )
851 input_ChangeArea( p_input,
852 p_input->stream.pp_areas[i_title] );
854 vlc_mutex_lock( &p_input->stream.stream_lock );
856 vlc_mutex_unlock( &p_input->stream.stream_lock );
860 void VlcWrapper::TitleInfo( int32 ¤tIndex, int32 &maxIndex )
866 vlc_mutex_lock( &p_input->stream.stream_lock );
868 maxIndex = p_input->stream.i_area_nb - 1;
870 currentIndex = p_input->stream.p_selected_area->i_id;
874 vlc_mutex_unlock( &p_input->stream.stream_lock );
878 bool VlcWrapper::HasChapters()
884 return ( p_input->stream.p_selected_area->i_part_nb > 1 );
887 BList * VlcWrapper::GetChapters()
891 vlc_mutex_lock( &p_input->stream.stream_lock );
893 BList *list = new BList( p_input->stream.p_selected_area->i_part_nb );
897 for( unsigned int i = 1;
898 i < p_input->stream.p_selected_area->i_part_nb + 1; i++ )
900 message = new BMessage( TOGGLE_CHAPTER );
901 message->AddInt32( "index", i );
902 BString helper( "" );
904 menuItem = new BMenuItem( helper.String(), message );
905 menuItem->SetMarked( p_input->stream.p_selected_area->i_part == i );
906 list->AddItem( menuItem );
909 vlc_mutex_unlock( &p_input->stream.stream_lock );
916 void VlcWrapper::PrevChapter()
919 i_id = p_input->stream.p_selected_area->i_part - 1;
926 void VlcWrapper::NextChapter()
929 i_id = p_input->stream.p_selected_area->i_part + 1;
936 void VlcWrapper::ToggleChapter(int i_chapter)
938 if( p_input != NULL )
940 p_input->stream.p_selected_area->i_part = i_chapter;
941 input_ChangeArea( p_input,
942 p_input->stream.p_selected_area );
944 vlc_mutex_lock( &p_input->stream.stream_lock );
945 vlc_mutex_unlock( &p_input->stream.stream_lock );
949 void VlcWrapper::ChapterInfo( int32 ¤tIndex, int32 &maxIndex )
955 vlc_mutex_lock( &p_input->stream.stream_lock );
957 maxIndex = p_input->stream.p_selected_area->i_part_nb - 1;
959 currentIndex = p_input->stream.p_selected_area->i_part;
963 vlc_mutex_unlock( &p_input->stream.stream_lock );
971 void VlcWrapper::LoadSubFile( const char * psz_file )
973 config_PutPsz( p_intf, "sub-file", strdup( psz_file ) );
976 void VlcWrapper::FilterChange()
981 vout_thread_t * p_vout;
982 vlc_mutex_lock( &p_input->stream.stream_lock );
984 // Warn the vout we are about to change the filter chain
985 p_vout = (vout_thread_t*)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
989 p_vout->b_filter_change = VLC_TRUE;
990 vlc_object_release( p_vout );
993 // restart all video stream
994 for( unsigned int i = 0; i < p_input->stream.i_es_number; i++ )
996 if( ( p_input->stream.pp_es[i]->i_cat == VIDEO_ES ) &&
997 ( p_input->stream.pp_es[i]->p_decoder_fifo != NULL ) )
999 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1000 input_SelectES( p_input, p_input->stream.pp_es[i] );
1003 vlc_mutex_unlock( &p_input->stream.stream_lock );