1 /*****************************************************************************
2 * intf_vlc_wrapper.c: MacOS X plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: intf_vlc_wrapper.m,v 1.6 2002/05/19 23:51:37 massiot Exp $
7 * Authors: Florian G. Pflug <fgp@phlo.org>
8 * Jon Lech Johansen <jon-vl@nanocrew.net>
9 * Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 #include <stdlib.h> /* malloc(), free() */
27 #include <sys/param.h> /* for MAXPATHLEN */
30 #include <IOKit/storage/IOCDMedia.h>
31 #include <IOKit/storage/IODVDMedia.h>
33 #include <videolan/vlc.h>
35 #include "interface.h"
36 #include "intf_playlist.h"
37 #include "intf_eject.h"
40 #include "video_output.h"
41 #include "audio_output.h"
43 #include "stream_control.h"
44 #include "input_ext-intf.h"
47 #include "intf_open.h"
48 #include "intf_vlc_wrapper.h"
52 @implementation Intf_VLCWrapper
54 static Intf_VLCWrapper *o_intf = nil;
58 + (Intf_VLCWrapper *)instance
62 o_intf = [[[Intf_VLCWrapper alloc] init] autorelease];
76 p_main->p_intf->pf_manage( p_main->p_intf );
78 if( p_main->p_intf->b_die )
80 /* Vout depends on intf */
89 if( p_input_bank->pp_input[0] != NULL )
91 vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
93 if( !p_input_bank->pp_input[0]->b_die )
95 /* New input or stream map change */
96 if( p_input_bank->pp_input[0]->stream.b_changed ||
97 p_main->p_intf->p_sys->i_part !=
98 p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
101 p_main->p_intf->p_sys->b_disabled_menus = 0;
105 vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
107 else if ( !p_main->p_intf->p_sys->b_disabled_menus )
110 p_main->p_intf->p_sys->b_disabled_menus = 1;
118 p_main->p_intf->b_die = 1;
121 /* playlist control */
125 if( p_input_bank->pp_input[0] != NULL )
127 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
128 p_main->p_playlist->b_stopped = 0;
132 vlc_mutex_lock( &p_main->p_playlist->change_lock );
134 if( p_main->p_playlist->b_stopped )
136 if( p_main->p_playlist->i_size )
138 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
139 intf_PlaylistJumpto( p_main->p_playlist,
140 p_main->p_playlist->i_index );
144 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
145 [[Intf_Open instance] openFile: nil];
150 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
157 - (void)playlistPause
159 if ( p_input_bank->pp_input[0] != NULL )
161 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PAUSE );
163 vlc_mutex_lock( &p_main->p_playlist->change_lock );
164 p_main->p_playlist->b_stopped = 0;
165 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
171 if( p_input_bank->pp_input[0] != NULL )
173 /* end playing item */
174 p_input_bank->pp_input[0]->b_eof = 1;
176 /* update playlist */
177 vlc_mutex_lock( &p_main->p_playlist->change_lock );
179 p_main->p_playlist->i_index--;
180 p_main->p_playlist->b_stopped = 1;
182 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
188 if( p_input_bank->pp_input[0] != NULL )
190 p_input_bank->pp_input[0]->b_eof = 1;
196 if( p_input_bank->pp_input[0] != NULL )
198 /* FIXME: temporary hack */
199 intf_PlaylistPrev( p_main->p_playlist );
200 intf_PlaylistPrev( p_main->p_playlist );
201 p_input_bank->pp_input[0]->b_eof = 1;
207 if( p_input_bank->pp_input[0] != NULL )
209 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_SLOWER );
211 vlc_mutex_lock( &p_main->p_playlist->change_lock );
212 p_main->p_playlist->b_stopped = 0;
213 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
219 if( p_input_bank->pp_input[0] != NULL )
221 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_FASTER );
223 vlc_mutex_lock( &p_main->p_playlist->change_lock );
224 p_main->p_playlist->b_stopped = 0;
225 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
231 if( p_aout_bank->pp_aout[0] == NULL ) return;
233 if( p_main->p_intf->p_sys->b_mute )
235 p_aout_bank->pp_aout[0]->i_volume =
236 p_main->p_intf->p_sys->i_saved_volume;
240 p_main->p_intf->p_sys->i_saved_volume =
241 p_aout_bank->pp_aout[0]->i_volume;
242 p_aout_bank->pp_aout[0]->i_volume = 0;
244 p_main->p_intf->p_sys->b_mute = !p_main->p_intf->p_sys->b_mute;
249 if( p_aout_bank->pp_aout[0] == NULL ) return;
251 if( p_main->p_intf->p_sys->b_mute )
253 p_main->p_intf->p_sys->i_saved_volume = VOLUME_MAX;
257 p_aout_bank->pp_aout[0]->i_volume = VOLUME_MAX;
263 if( p_vout_bank->pp_vout[0] != NULL )
265 p_vout_bank->pp_vout[0]->i_changes |= VOUT_FULLSCREEN_CHANGE;
271 /* FIXME : this will only eject the first drive found */
272 NSArray * o_devices = GetEjectableMediaOfClass(kIODVDMediaClass);
273 const char * psz_device;
275 if ( p_input_bank->pp_input[0] != NULL &&
276 (p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_VCD ||
277 p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DVD ||
278 p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DISC) )
280 intf_ErrMsg("error: cannot eject the disc while you're reading from it");
284 if ( o_devices == nil )
286 o_devices = GetEjectableMediaOfClass(kIOCDMediaClass);
289 if ( o_devices != nil && [o_devices count] )
291 psz_device = [[o_devices objectAtIndex:0] cString];
292 intf_Eject( psz_device );
298 #define p_area p_input_bank->pp_input[0]->stream.p_selected_area
300 - (NSString *)getTimeAsString
302 static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
304 if( p_input_bank->pp_input[0] == NULL )
306 return [NSString stringWithCString:"00:00:00"];
309 input_OffsetToTime( p_input_bank->pp_input[0],
310 psz_currenttime, p_area->i_tell );
312 return( [NSString stringWithCString: psz_currenttime] );
315 - (float)getTimeAsFloat
319 if( p_input_bank->pp_input[0] != NULL )
321 f_time = (float)p_area->i_tell / (float)p_area->i_size;
327 - (void)setTimeAsFloat:(float)f_position
329 if( p_input_bank->pp_input[0] != NULL )
331 input_Seek( p_input_bank->pp_input[0], p_area->i_size * f_position );
337 - (bool)playlistPlaying
339 return( !p_main->p_playlist->b_stopped );
342 - (NSArray *)playlistAsArray
345 NSMutableArray* p_list =
346 [NSMutableArray arrayWithCapacity: p_main->p_playlist->i_size];
348 vlc_mutex_lock( &p_main->p_playlist->change_lock );
350 for( i = 0; i < p_main->p_playlist->i_size; i++ )
352 [p_list addObject: [NSString
353 stringWithCString: p_main->p_playlist->p_item[i].psz_name]];
356 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
358 return( [NSArray arrayWithArray: p_list] );
362 - (int)playlistLength
364 return( p_main->p_playlist->i_size );
367 - (NSString*)playlistItem:(int)i_pos
369 NSString *o_item = nil;
371 vlc_mutex_lock( &p_main->p_playlist->change_lock );
373 if( i_pos < p_main->p_playlist->i_size )
376 stringWithCString: p_main->p_playlist->p_item[i_pos].psz_name];
379 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
384 - (void)playlistPlayItem:(int)i_item
388 vlc_mutex_lock( &p_main->p_playlist->change_lock );
390 if( i_item<p_main->p_playlist->i_size )
392 p_main->p_playlist->i_index--;
395 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
397 [self playlistPlayCurrent];
400 - (void)playlistAdd:(NSString *)o_filename
402 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
403 [o_filename lossyCString] );
406 - (void)clearPlaylist
410 vlc_mutex_lock( &p_main->p_playlist->change_lock );
412 for( i = 0; i < p_main->p_playlist->i_size; i++ )
414 intf_PlaylistDelete( p_main->p_playlist, i );
417 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
421 /* open file/disc/network */
423 - (void)openFiles:(NSArray*)o_files
426 int i_end = p_main->p_playlist->i_size;
427 NSEnumerator *o_enum = [o_files objectEnumerator];
429 while( ( o_file = (NSString *)[o_enum nextObject] ) )
431 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
432 [o_file lossyCString] );
435 /* end current item, select first added item */
436 if( p_input_bank->pp_input[0] != NULL )
438 p_input_bank->pp_input[0]->b_eof = 1;
441 intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
444 - (void)openDisc:(NSString*)o_type device:(NSString*)o_device title:(int)i_title chapter:(int)i_chapter
447 int i_end = p_main->p_playlist->i_size;
449 o_source = [NSString stringWithFormat: @"%@:%@@%d,%d",
450 o_type, o_device, i_title, i_chapter];
452 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
453 [o_source lossyCString] );
455 /* stop current item, select added item */
456 if( p_input_bank->pp_input[0] != NULL )
458 p_input_bank->pp_input[0]->b_eof = 1;
461 intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
464 - (void)openNet:(NSString*)o_protocol addr:(NSString*)o_addr port:(int)i_port baddr:(NSString*)o_baddr
467 int i_end = p_main->p_playlist->i_size;
469 if( p_input_bank->pp_input[0] != NULL )
471 p_input_bank->pp_input[0]->b_eof = 1;
474 config_PutIntVariable( "network_channel", 0 );
478 o_source = [NSString stringWithFormat: @"%@://%@@:%i/%@",
479 o_protocol, o_addr, i_port, o_baddr];
483 o_source = [NSString stringWithFormat: @"%@://%@@:%i",
484 o_protocol, o_addr, i_port];
487 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
488 [o_source lossyCString] );
490 intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
493 - (void)openNetChannel:(NSString*)o_addr port:(int)i_port
495 if( p_input_bank->pp_input[0] != NULL )
497 p_input_bank->pp_input[0]->b_eof = 1;
500 config_PutIntVariable( "network_channel", 1 );
502 if( p_main->p_channel == NULL )
504 network_ChannelCreate();
507 config_PutPszVariable( "channel_server", (char*)[o_addr lossyCString] );
508 config_PutIntVariable( "channel_port", i_port );
511 - (void)toggleProgram:(id)sender
513 NSMenuItem * o_item = (NSMenuItem *)sender;
514 input_thread_t * p_input = p_input_bank->pp_input[0];
516 if( [o_item state] == NSOffState )
518 u16 i_program_id = [o_item tag];
520 input_ChangeProgram( p_input, i_program_id );
522 vlc_mutex_lock( &p_input->stream.stream_lock );
524 vlc_mutex_unlock( &p_input->stream.stream_lock );
526 input_SetStatus( p_input, INPUT_STATUS_PLAY );
530 - (void)toggleTitle:(id)sender
532 NSMenuItem * o_item = (NSMenuItem *)sender;
533 input_thread_t * p_input = p_input_bank->pp_input[0];
535 if( [o_item state] == NSOffState )
537 int i_title = [o_item tag];
539 input_ChangeArea( p_input,
540 p_input->stream.pp_areas[i_title] );
542 vlc_mutex_lock( &p_input->stream.stream_lock );
544 vlc_mutex_unlock( &p_input->stream.stream_lock );
546 input_SetStatus( p_input, INPUT_STATUS_PLAY );
550 - (void)toggleChapter:(id)sender
552 NSMenuItem * o_item = (NSMenuItem *)sender;
553 input_thread_t * p_input = p_input_bank->pp_input[0];
555 if( [o_item state] == NSOffState )
557 int i_chapter = [o_item tag];
559 p_input->stream.p_selected_area->i_part = i_chapter;
560 input_ChangeArea( p_input,
561 p_input->stream.p_selected_area );
563 vlc_mutex_lock( &p_input->stream.stream_lock );
565 vlc_mutex_unlock( &p_input->stream.stream_lock );
567 input_SetStatus( p_input, INPUT_STATUS_PLAY );
571 - (void)toggleLanguage:(id)sender
573 NSMenuItem * o_item = (NSMenuItem *)sender;
574 input_thread_t * p_input = p_input_bank->pp_input[0];
576 int i_es = [o_item tag];
578 if( [o_item state] == NSOnState )
580 /* We just have one ES to disable */
581 input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
585 /* Unselect the selected ES in the same class */
587 vlc_mutex_lock( &p_input->stream.stream_lock );
588 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
590 if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
592 vlc_mutex_unlock( &p_input->stream.stream_lock );
593 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
594 vlc_mutex_lock( &p_input->stream.stream_lock );
598 vlc_mutex_unlock( &p_input->stream.stream_lock );
600 /* Select the wanted ES */
601 input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
604 vlc_mutex_lock( &p_input->stream.stream_lock );
606 vlc_mutex_unlock( &p_input->stream.stream_lock );
608 input_SetStatus( p_input, INPUT_STATUS_PLAY );
611 - (void)toggleSubtitle:(id)sender
613 NSMenuItem * o_item = (NSMenuItem *)sender;
614 input_thread_t * p_input = p_input_bank->pp_input[0];
616 int i_es = [o_item tag];
618 if( [o_item state] == NSOnState )
620 /* We just have one ES to disable */
621 input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
625 /* Unselect the selected ES in the same class */
627 vlc_mutex_lock( &p_input->stream.stream_lock );
628 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
630 if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
632 vlc_mutex_unlock( &p_input->stream.stream_lock );
633 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
634 vlc_mutex_lock( &p_input->stream.stream_lock );
638 vlc_mutex_unlock( &p_input->stream.stream_lock );
640 /* Select the wanted ES */
641 input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
644 vlc_mutex_lock( &p_input->stream.stream_lock );
646 vlc_mutex_unlock( &p_input->stream.stream_lock );
648 input_SetStatus( p_input, INPUT_STATUS_PLAY );
654 NSMenuItem *o_controls_item;
655 NSMenuItem *o_program_item, *o_title_item, *o_chapter_item, *o_language_item,
657 input_thread_t * p_input = p_input_bank->pp_input[0];
659 o_main_menu = [NSApp mainMenu];
660 o_controls_item = [o_main_menu itemWithTitle: @"Controls"];
661 o_program_item = [[o_controls_item submenu] itemWithTitle: @"Program"];
662 o_title_item = [[o_controls_item submenu] itemWithTitle: @"Title"];
663 o_chapter_item = [[o_controls_item submenu] itemWithTitle: @"Chapter"];
664 o_language_item = [[o_controls_item submenu] itemWithTitle: @"Language"];
665 o_subtitle_item = [[o_controls_item submenu] itemWithTitle: @"Subtitles"];
667 if( p_input == NULL )
669 [o_program_item setEnabled:0];
670 [o_title_item setEnabled:0];
671 [o_chapter_item setEnabled:0];
672 [o_language_item setEnabled:0];
673 [o_subtitle_item setEnabled:0];
677 NSMenu *o_program, *o_title, *o_chapter, *o_language, *o_subtitle;
678 SEL pf_toggle_program, pf_toggle_title, pf_toggle_chapter,
679 pf_toggle_language, pf_toggle_subtitle;
682 pgrm_descriptor_t * p_pgrm;
684 /* ----- PROGRAMS ----- */
685 if( p_input->stream.i_pgrm_number < 2 )
687 [o_program_item setEnabled:0];
691 [o_program_item setEnabled:1];
692 o_program = [o_program_item submenu];
693 pf_toggle_program = @selector(toggleProgram:);
695 /* Remove previous program menu */
696 i_nb_items = [o_program numberOfItems];
697 for( i = 0; i < i_nb_items; i++ )
699 [o_program removeItemAtIndex:0];
702 if( p_input->stream.p_new_program )
704 p_pgrm = p_input->stream.p_new_program;
708 p_pgrm = p_input->stream.p_selected_program;
711 /* Create program menu */
712 for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ )
714 char psz_title[ 256 ];
715 NSString * o_menu_title;
718 snprintf( psz_title, sizeof(psz_title), "id %d",
719 p_input->stream.pp_programs[i]->i_number );
720 psz_title[sizeof(psz_title) - 1] = '\0';
722 o_menu_title = [NSString stringWithCString: psz_title];
724 o_item = [o_program addItemWithTitle: o_menu_title
725 action: pf_toggle_program keyEquivalent: @""];
726 [o_item setTarget: self];
727 [o_item setTag: p_input->stream.pp_programs[i]->i_number];
728 if( p_pgrm == p_input->stream.pp_programs[i] )
730 [o_item setState: 1];
734 vlc_mutex_unlock( &p_input->stream.stream_lock );
735 vlc_mutex_lock( &p_input->stream.stream_lock );
737 /* ----- TITLES ----- */
738 if( p_input->stream.i_area_nb < 2 )
740 [o_title_item setEnabled:0];
744 [o_title_item setEnabled:1];
745 o_title = [o_title_item submenu];
746 pf_toggle_title = @selector(toggleTitle:);
748 /* Remove previous title menu */
749 i_nb_items = [o_title numberOfItems];
750 for( i = 0; i < i_nb_items; i++ )
752 [o_title removeItemAtIndex:0];
755 /* Create title menu */
756 for( i = 1 ; i < p_input->stream.i_area_nb ; i++ )
758 char psz_title[ 256 ];
759 NSString * o_menu_title;
762 snprintf( psz_title, sizeof(psz_title), "Title %d (%d)", i,
763 p_input->stream.pp_areas[i]->i_part_nb );
764 psz_title[sizeof(psz_title) - 1] = '\0';
766 o_menu_title = [NSString stringWithCString: psz_title];
768 o_item = [o_title addItemWithTitle: o_menu_title
769 action: pf_toggle_title keyEquivalent: @""];
771 [o_item setTarget: self];
772 if( ( p_input->stream.pp_areas[i] ==
773 p_input->stream.p_selected_area ) )
775 [o_item setState: 1];
779 vlc_mutex_unlock( &p_input->stream.stream_lock );
780 vlc_mutex_lock( &p_input->stream.stream_lock );
782 /* ----- CHAPTERS ----- */
783 if( p_input->stream.p_selected_area->i_part_nb < 2 )
785 [o_chapter_item setEnabled:0];
789 [o_chapter_item setEnabled:1];
790 o_chapter = [o_chapter_item submenu];
791 pf_toggle_chapter = @selector(toggleChapter:);
793 /* Remove previous chapter menu */
794 i_nb_items = [o_chapter numberOfItems];
795 for( i = 0; i < i_nb_items; i++ )
797 [o_chapter removeItemAtIndex:0];
800 /* Create chapter menu */
801 for( i = 0 ; i < p_input->stream.p_selected_area->i_part_nb ; i++ )
803 char psz_title[ 256 ];
804 NSString * o_menu_title;
807 snprintf( psz_title, sizeof(psz_title), "Chapter %d", i + 1 );
808 psz_title[sizeof(psz_title) - 1] = '\0';
810 o_menu_title = [NSString stringWithCString: psz_title];
812 o_item = [o_chapter addItemWithTitle: o_menu_title
813 action: pf_toggle_chapter keyEquivalent: @""];
815 [o_item setTarget: self];
816 if( ( p_input->stream.p_selected_area->i_part == i + 1 ) )
818 [o_item setState: 1];
822 p_main->p_intf->p_sys->i_part = p_input->stream.p_selected_area->i_part;
823 vlc_mutex_unlock( &p_input->stream.stream_lock );
824 vlc_mutex_lock( &p_input->stream.stream_lock );
826 /* ----- LANGUAGES & SUBTITLES ----- */
827 o_language = [o_language_item submenu];
828 o_subtitle = [o_subtitle_item submenu];
829 pf_toggle_language = @selector(toggleLanguage:);
830 pf_toggle_subtitle = @selector(toggleSubtitle:);
832 /* Remove previous language menu */
833 i_nb_items = [o_language numberOfItems];
834 for( i = 0; i < i_nb_items; i++ )
836 [o_language removeItemAtIndex:0];
839 /* Remove previous subtitle menu */
840 i_nb_items = [o_subtitle numberOfItems];
841 for( i = 0; i < i_nb_items; i++ )
843 [o_subtitle removeItemAtIndex:0];
846 /* Create language & subtitles menus */
847 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
849 es_descriptor_t * p_es = p_input->stream.pp_es[i];
850 if( p_es->p_pgrm != NULL
851 && p_es->p_pgrm != p_input->stream.p_selected_program )
856 if( p_es->i_cat == AUDIO_ES )
858 NSString * o_menu_title;
861 if( *p_es->psz_desc )
863 o_menu_title = [NSString stringWithCString: p_es->psz_desc];
867 char psz_title[ 256 ];
868 snprintf( psz_title, sizeof(psz_title), "Language 0x%x",
870 psz_title[sizeof(psz_title) - 1] = '\0';
872 o_menu_title = [NSString stringWithCString: psz_title];
875 o_item = [o_language addItemWithTitle: o_menu_title
876 action: pf_toggle_language keyEquivalent: @""];
878 [o_item setTarget: self];
879 if( p_es->p_decoder_fifo != NULL )
881 [o_item setState: 1];
884 else if( p_es->i_cat == SPU_ES )
886 NSString * o_menu_title;
889 if( *p_es->psz_desc )
891 o_menu_title = [NSString stringWithCString: p_es->psz_desc];
895 char psz_title[ 256 ];
896 snprintf( psz_title, sizeof(psz_title), "Subtitle 0x%x",
898 psz_title[sizeof(psz_title) - 1] = '\0';
900 o_menu_title = [NSString stringWithCString: psz_title];
903 o_item = [o_subtitle addItemWithTitle: o_menu_title
904 action: pf_toggle_subtitle keyEquivalent: @""];
906 [o_item setTarget: self];
907 if( p_es->p_decoder_fifo != NULL )
909 [o_item setState: 1];
914 if( [o_language numberOfItems] )
916 [o_language_item setEnabled: 1];
920 [o_language_item setEnabled: 0];
922 if( [o_subtitle numberOfItems] )
924 [o_subtitle_item setEnabled: 1];
928 [o_subtitle_item setEnabled: 0];
930 p_input->stream.b_changed = 0;