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 $
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()
101 return p_input->stream.control.i_status;
104 int VlcWrapper::InputRate()
109 return p_input->stream.control.i_rate;
112 void VlcWrapper::InputSetRate( int rate )
118 int oldrate = InputRate();
119 switch( ( rate > oldrate ) ? ( rate / oldrate ) : ( oldrate / rate ) )
141 int newrate = oldrate;
142 for( int i = 0; i < times; i++ )
146 input_SetStatus( p_input, INPUT_STATUS_SLOWER );
151 input_SetStatus( p_input, INPUT_STATUS_FASTER );
154 /* Wait it's actually done */
155 while( InputRate() != newrate )
160 BList * VlcWrapper::GetChannels( int i_cat )
166 const char* fieldName;
172 what = SELECT_CHANNEL;
173 fieldName = "channel";
178 what = SELECT_SUBTITLE;
179 fieldName = "subtitle";
186 vlc_mutex_lock( &p_input->stream.stream_lock );
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++ )
192 if( p_input->stream.pp_selected_es[i]->i_cat == i_cat )
193 p_es = p_input->stream.pp_selected_es[i];
196 /* build a list of all tracks */
197 BList *list = new BList( p_input->stream.i_es_number );
203 message = new BMessage( what );
204 message->AddInt32( fieldName, -1 );
205 menuItem = new BMenuItem( _("None"), message );
207 menuItem->SetMarked( true );
208 list->AddItem( menuItem );
210 for( i = 0; i < p_input->stream.i_es_number; i++ )
212 if( p_input->stream.pp_es[i]->i_cat == i_cat )
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>");
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 );
228 vlc_mutex_unlock( &p_input->stream.stream_lock );
235 void VlcWrapper::ToggleLanguage( int i_language )
237 es_descriptor_t * p_es = NULL;
238 es_descriptor_t * p_es_old = NULL;
240 vlc_mutex_lock( &p_input->stream.stream_lock );
241 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
243 if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
245 p_es_old = p_input->stream.pp_selected_es[i];
249 vlc_mutex_unlock( &p_input->stream.stream_lock );
251 if( i_language != -1 )
253 p_es = p_input->stream.pp_es[i_language];
255 if( p_es == p_es_old )
261 input_ToggleES( p_input, p_es_old, VLC_FALSE );
265 input_ToggleES( p_input, p_es, VLC_TRUE );
269 void VlcWrapper::ToggleSubtitle( int i_subtitle )
271 es_descriptor_t * p_es = NULL;
272 es_descriptor_t * p_es_old = NULL;
274 vlc_mutex_lock( &p_input->stream.stream_lock );
275 for( unsigned int i = 0; i < p_input->stream.i_selected_es_number ; i++ )
277 if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
279 p_es_old = p_input->stream.pp_selected_es[i];
283 vlc_mutex_unlock( &p_input->stream.stream_lock );
285 if( i_subtitle != -1 )
287 p_es = p_input->stream.pp_es[i_subtitle];
289 if( p_es == p_es_old )
295 input_ToggleES( p_input, p_es_old, VLC_FALSE );
299 input_ToggleES( p_input, p_es, VLC_TRUE );
303 const char * VlcWrapper::GetTimeAsString()
305 static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
307 if( p_input == NULL )
312 input_OffsetToTime( p_input,
314 p_input->stream.p_selected_area->i_tell );
316 return(psz_currenttime);
319 float VlcWrapper::GetTimeAsFloat()
323 if( p_input != NULL )
325 f_time = (float)p_input->stream.p_selected_area->i_tell /
326 (float)p_input->stream.p_selected_area->i_size;
335 void VlcWrapper::SetTimeAsFloat( float f_position )
337 if( p_input != NULL )
340 (long long)(p_input->stream.p_selected_area->i_size
341 * f_position / SEEKSLIDER_RANGE ),
346 bool VlcWrapper::IsPlaying()
349 bool playing = false;
352 switch ( p_input->stream.control.i_status )
375 void VlcWrapper::OpenFiles( BList* o_files, bool replace, int32 index )
377 if ( o_files && o_files->CountItems() > 0)
379 int size = PlaylistSize();
380 bool wasEmpty = ( size < 1 );
382 index = PLAYLIST_END;
383 int mode = index == PLAYLIST_END ? PLAYLIST_APPEND : PLAYLIST_INSERT;
385 /* delete current playlist */
388 for( int i = 0; i < size; i++ )
390 playlist_Delete( p_playlist, 0 );
395 int32 count = o_files->CountItems();
396 for ( int32 i = count - 1; i >= 0; i-- )
398 if ( BString* o_file = (BString *)o_files->RemoveItem( i ) )
400 playlist_Add( p_playlist, o_file->String(),
402 if ( mode == PLAYLIST_INSERT )
407 // TODO: implement a user setting
408 // if to start automatically
409 /* eventually restart playing */
410 if( replace || wasEmpty )
412 playlist_Stop( p_playlist );
413 playlist_Play( p_playlist );
418 void VlcWrapper::OpenDisc(BString o_type, BString o_device, int i_title, int i_chapter)
420 if( config_GetInt( p_intf, "beos-dvdmenus" ) )
421 o_device.Prepend( "dvdplay:" );
423 o_device.Prepend( "dvdold:" );
424 playlist_Add( p_playlist, o_device.String(),
425 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
428 int VlcWrapper::PlaylistSize()
430 vlc_mutex_lock( &p_playlist->object_lock );
431 int i_size = p_playlist->i_size;
432 vlc_mutex_unlock( &p_playlist->object_lock );
436 char * VlcWrapper::PlaylistItemName( int i )
438 return p_playlist->pp_items[i]->psz_name;
441 int VlcWrapper::PlaylistCurrent()
443 return p_playlist->i_index;
446 bool VlcWrapper::PlaylistPlay()
450 playlist_Play( p_playlist );
455 void VlcWrapper::PlaylistPause()
459 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
463 void VlcWrapper::PlaylistStop()
465 playlist_Stop( p_playlist );
468 void VlcWrapper::PlaylistNext()
470 playlist_Next( p_playlist );
473 void VlcWrapper::PlaylistPrev()
475 playlist_Prev( p_playlist );
478 void VlcWrapper::GetPlaylistInfo( int32& currentIndex, int32& maxIndex )
484 vlc_mutex_lock( &p_playlist->object_lock );
486 maxIndex = p_playlist->i_size;
488 currentIndex = p_playlist->i_index/* + 1 -> why?!?*/;
492 vlc_mutex_unlock( &p_playlist->object_lock );
496 void VlcWrapper::PlaylistJumpTo( int pos )
498 playlist_Goto( p_playlist, pos );
501 void VlcWrapper::GetNavCapabilities( bool *canSkipPrev, bool *canSkipNext )
503 if ( canSkipPrev && canSkipNext )
505 // init the parameters
506 *canSkipPrev = false;
507 *canSkipNext = false;
509 int pos = PlaylistCurrent();
510 int size = PlaylistSize();
512 // see if we have got a stream going
515 vlc_mutex_lock( &p_input->stream.stream_lock );
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
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;
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;
535 vlc_mutex_unlock( &p_input->stream.stream_lock );
537 // last but not least, make capabilities depend on playlist
539 *canSkipPrev = pos > 0;
541 *canSkipNext = pos < size - 1;
545 void VlcWrapper::NavigatePrev()
547 bool hasSkiped = false;
549 // see if we have got a stream going
552 // get information from stream (lock it while looking at it)
553 vlc_mutex_lock( &p_input->stream.stream_lock );
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;
562 vlc_mutex_unlock( &p_input->stream.stream_lock );
564 // first, look for chapters
567 // skip to the previous chapter
570 if ( currentChapter >= 0 )
572 ToggleChapter( currentChapter );
576 // if we couldn't skip chapters, try titles instead
577 if ( !hasSkiped && hasTitles )
579 // skip to the previous title
581 // disallow area 0 since it is used for video_ts.vob
582 if( currentTitle > 0 )
584 ToggleTitle(currentTitle);
590 // last but not least, skip to previous file
595 void VlcWrapper::NavigateNext()
597 bool hasSkiped = false;
599 // see if we have got a stream going
602 // get information from stream (lock it while looking at it)
603 vlc_mutex_lock( &p_input->stream.stream_lock );
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;
612 vlc_mutex_unlock( &p_input->stream.stream_lock );
614 // first, look for chapters
617 // skip to the next chapter
619 if ( currentChapter < numChapters )
621 ToggleChapter( currentChapter );
625 // if we couldn't skip chapters, try titles instead
626 if ( !hasSkiped && hasTitles )
628 // skip to the next title
630 // disallow area 0 since it is used for video_ts.vob
631 if ( currentTitle < numTitles - 1 )
633 ToggleTitle(currentTitle);
639 // last but not least, skip to next file
644 /*************************
645 * Playlist manipulation *
646 *************************/
650 VlcWrapper::PlaylistLock() const
652 // TODO: search and destroy -> deadlock!
656 vlc_mutex_lock( &p_playlist->object_lock );
664 VlcWrapper::PlaylistUnlock() const
666 // TODO: search and destroy -> deadlock!
668 vlc_mutex_unlock( &p_playlist->object_lock );
673 VlcWrapper::PlaylistItemAt( int index ) const
675 playlist_item_t* item = NULL;
676 if ( index >= 0 && index < p_playlist->i_size )
677 item = p_playlist->pp_items[index];
681 // PlaylistRemoveItem
683 VlcWrapper::PlaylistRemoveItem( int index ) const
685 playlist_item_t* copy = NULL;
686 // check if item exists at the provided index
687 if ( index >= 0 && index < p_playlist->i_size )
689 playlist_item_t* item = p_playlist->pp_items[index];
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 );
701 // PlaylistRemoveItem
703 VlcWrapper::PlaylistRemoveItem( void* item ) const
705 playlist_item_t* copy = NULL;
706 for ( int32 i = 0; i < p_playlist->i_size; i++ )
708 if ( p_playlist->pp_items[i] == item )
710 copy = (playlist_item_t*)PlaylistRemoveItem( i );
719 VlcWrapper::PlaylistAddItem( void* item, int index ) const
723 playlist_AddItem( p_playlist, (playlist_item_t*)item,
724 PLAYLIST_INSERT, index );
726 // TODO: once playlist is returning useful info, return that instead
732 VlcWrapper::PlaylistCloneItem( void* castToItem ) const
734 playlist_item_t* copy = NULL;
735 playlist_item_t* item = (playlist_item_t*)castToItem;
738 copy = (playlist_item_t*)malloc( sizeof( playlist_item_t ) );
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;
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.
758 // PlaylistSetPlaying
760 VlcWrapper::PlaylistSetPlaying( int index ) const
764 if ( index >= p_playlist->i_size )
765 index = p_playlist->i_size - 1;
766 p_playlist->i_index = index;
774 unsigned short VlcWrapper::GetVolume()
776 unsigned short i_volume;
777 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
781 void VlcWrapper::SetVolume( int value )
783 if ( p_intf->p_sys->b_mute )
785 p_intf->p_sys->b_mute = 0;
787 aout_VolumeSet( p_intf, value );
790 void VlcWrapper::VolumeMute()
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;
797 void VlcWrapper::VolumeRestore()
799 aout_VolumeSet( p_intf, p_intf->p_sys->i_saved_volume );
800 p_intf->p_sys->b_mute = 0;
803 bool VlcWrapper::IsMuted()
805 return p_intf->p_sys->b_mute;
812 bool VlcWrapper::HasTitles()
818 return ( p_input->stream.i_area_nb > 1 );
821 BList * VlcWrapper::GetTitles()
825 vlc_mutex_lock( &p_input->stream.stream_lock );
827 BList *list = new BList( p_input->stream.i_area_nb );
831 for( unsigned int i = 1; i < p_input->stream.i_area_nb; i++ )
833 message = new BMessage( TOGGLE_TITLE );
834 message->AddInt32( "index", i );
835 BString helper( "" );
837 menuItem = new BMenuItem( helper.String(), message );
838 menuItem->SetMarked( p_input->stream.p_selected_area->i_id == i );
839 list->AddItem( menuItem );
842 vlc_mutex_unlock( &p_input->stream.stream_lock );
849 void VlcWrapper::PrevTitle()
852 i_id = p_input->stream.p_selected_area->i_id - 1;
859 void VlcWrapper::NextTitle()
862 i_id = p_input->stream.p_selected_area->i_id + 1;
863 if( i_id < p_input->stream.i_area_nb )
869 void VlcWrapper::ToggleTitle(int i_title)
871 if( p_input != NULL )
873 input_ChangeArea( p_input,
874 p_input->stream.pp_areas[i_title] );
876 vlc_mutex_lock( &p_input->stream.stream_lock );
878 vlc_mutex_unlock( &p_input->stream.stream_lock );
882 void VlcWrapper::TitleInfo( int32 ¤tIndex, int32 &maxIndex )
888 vlc_mutex_lock( &p_input->stream.stream_lock );
890 maxIndex = p_input->stream.i_area_nb - 1;
892 currentIndex = p_input->stream.p_selected_area->i_id;
896 vlc_mutex_unlock( &p_input->stream.stream_lock );
900 bool VlcWrapper::HasChapters()
906 return ( p_input->stream.p_selected_area->i_part_nb > 1 );
909 BList * VlcWrapper::GetChapters()
913 vlc_mutex_lock( &p_input->stream.stream_lock );
915 BList *list = new BList( p_input->stream.p_selected_area->i_part_nb );
919 for( unsigned int i = 1;
920 i < p_input->stream.p_selected_area->i_part_nb + 1; i++ )
922 message = new BMessage( TOGGLE_CHAPTER );
923 message->AddInt32( "index", i );
924 BString helper( "" );
926 menuItem = new BMenuItem( helper.String(), message );
927 menuItem->SetMarked( p_input->stream.p_selected_area->i_part == i );
928 list->AddItem( menuItem );
931 vlc_mutex_unlock( &p_input->stream.stream_lock );
938 void VlcWrapper::PrevChapter()
941 i_id = p_input->stream.p_selected_area->i_part - 1;
948 void VlcWrapper::NextChapter()
951 i_id = p_input->stream.p_selected_area->i_part + 1;
958 void VlcWrapper::ToggleChapter(int i_chapter)
960 if( p_input != NULL )
962 p_input->stream.p_selected_area->i_part = i_chapter;
963 input_ChangeArea( p_input,
964 p_input->stream.p_selected_area );
966 vlc_mutex_lock( &p_input->stream.stream_lock );
967 vlc_mutex_unlock( &p_input->stream.stream_lock );
971 void VlcWrapper::ChapterInfo( int32 ¤tIndex, int32 &maxIndex )
977 vlc_mutex_lock( &p_input->stream.stream_lock );
979 maxIndex = p_input->stream.p_selected_area->i_part_nb - 1;
981 currentIndex = p_input->stream.p_selected_area->i_part;
985 vlc_mutex_unlock( &p_input->stream.stream_lock );
993 void VlcWrapper::LoadSubFile( const char * psz_file )
995 config_PutPsz( p_intf, "sub-file", strdup( psz_file ) );
998 void VlcWrapper::FilterChange()
1003 vout_thread_t * p_vout;
1004 vlc_mutex_lock( &p_input->stream.stream_lock );
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,
1011 p_vout->b_filter_change = VLC_TRUE;
1012 vlc_object_release( p_vout );
1015 // restart all video stream
1016 for( unsigned int i = 0; i < p_input->stream.i_es_number; i++ )
1018 if( ( p_input->stream.pp_es[i]->i_cat == VIDEO_ES ) &&
1019 ( p_input->stream.pp_es[i]->p_decoder_fifo != NULL ) )
1021 input_UnselectES( p_input, p_input->stream.pp_es[i] );
1022 input_SelectES( p_input, p_input->stream.pp_es[i] );
1025 vlc_mutex_unlock( &p_input->stream.stream_lock );